用javassist生成一个类(字节码文件)
/**
* 使用javassist生成一个新的类
* @author L J
*/
public class JavassistDemo {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("com.belief.compiler.bean.Emp");
//创建属性
CtField f1 = CtField.make("private Integer empno;", cc);
CtField f2 = CtField.make("private String ename;", cc);
//向类中添加属性
cc.addField(f1);
cc.addField(f2);
//创建方法
CtMethod m1 = CtMethod.make("public Integer getEmpno() {return empno;}", cc);
CtMethod m2 = CtMethod.make("public void setEmpno(Integer empno) {this.empno = empno;}", cc);
//向类中添加方法
cc.addMethod(m1);
cc.addMethod(m2);
//创建构造器
CtConstructor constructor = new CtConstructor(new CtClass[]{pool.get("java.lang.Integer"), pool.get("java.lang.String")}, cc);
constructor.setBody("{this.empno = empno; this.ename = ename;}");
cc.addConstructor(constructor);
//将上面的类写到F:/DB中
cc.writeFile("F:/DB");
}
}
以上代码生成的是字节码文件,需要用反编译工具XJad反编译后进行查看
javassist的API
//作者注解
public @interface Author {
String name();
int year();
}
//员工类
@Author(name="jack", year=2017)
public class Emp implements Serializable{
//员工编号
private Integer empno;
//员工姓名
private String ename;
public Emp() {
}
public Emp(Integer empno, String ename) {
this.empno = empno;
this.ename = ename;
}
public void sayHello(String str) {
System.out.println("hello, " + str);
}
public Integer getEmpno() {
return empno;
}
public void setEmpno(Integer empno) {
this.empno = empno;
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
}
/**
* 测试javassist的API
* @author L J
*/
@SuppressWarnings("all")
public class JavassitDemo2 {
public static void main(String[] args) throws Exception {
test06();
}
/**
* 处理类的基本用法
* @throws Exception
*/
public static void test01() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
byte[] bytes = cc.toBytecode();
System.out.println(Arrays.toString(bytes));
System.out.println(cc.getName()); //获取类名
System.out.println(cc.getSimpleName()); //获取简要类名
System.out.println(cc.getSuperclass()); //获取父类
System.out.println(cc.getInterfaces()); //获取接口
}
/**
* 测试产生新的方法
* @throws Exception
*/
public static void test02() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
//CtMethod m = CtMethod.make("public int add(int a, int b){return a + b;}", cc);
//参数解释:1、返回值类型 2、方法名 3、参数类型(数组)
CtMethod m = new CtMethod(CtClass.intType, "add", new CtClass[]{
CtClass.intType, CtClass.intType
}, cc);
//设置方法的修饰符
m.setModifiers(Modifier.PUBLIC);
//设置方法体
m.setBody("{return $1 + $2;}");
cc.addMethod(m);
//通过反射调用所生成的方法
Class clazz = cc.toClass();
//通过调用Emp的无参构造器,创建新的Emp对象
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("add", int.class, int.class);
Object result = method.invoke(obj, 200, 30);
System.out.println(result); //230
}
/**
* 获取已有的方法,并对其进行修改
* @throws Exception
*/
public static void test03() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
//反射得到方法
CtMethod cm = cc.getDeclaredMethod("sayHello", new CtClass[] {
pool.get("java.lang.String")
});
//在方法体前面加代码
cm.insertBefore("System.out.println($1);System.out.println(\"start!\");");
//在指定行的前面加代码
cm.insertAt(21, "int b = 3; System.out.println(\"b = \" + b);");
//在方法体后面加代码
cm.insertAfter("System.out.println(\"end!\");");
//通过反射调用所生成的方法
Class clazz = cc.toClass();
//通过调用Emp的无参构造器,创建新的Emp对象
Object obj = clazz.newInstance();
Method method = clazz.getDeclaredMethod("sayHello", String.class);
method.invoke(obj, "香茗");
}
/**
* 操作属性
* @throws Exception
*/
public static void test04() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
//CtField f1 = CtField.make("private double salary;", cc);
//参数解释:1、要新建的属性类型 2、要新建的属性名称
CtField f1 = new CtField(CtClass.intType, "salary", cc);
//设置属性的修饰符
f1.setModifiers(Modifier.PRIVATE);
//将属性添加到类中,并设置默认值
cc.addField(f1, "5000.0");
//增加相应的set和get方法
cc.addMethod(CtNewMethod.getter("getSalary", f1));
cc.addMethod(CtNewMethod.getter("setSalary", f1));
}
/**
* 操作构造器
* @throws Exception
*/
public static void test05() throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.belief.compiler.Emp");
//取得所有的构造器
CtConstructor[] cs = cc.getConstructors();
for (CtConstructor c : cs) {
System.out.println(c.getLongName());
}
}
/**
* 操作注解
* @throws Exception
*/
public static void test06() throws Exception {
CtClass cc = ClassPool.getDefault().get("com.belief.compiler.Emp");
//获取注解
Object[] all = cc.getAnnotations();
Author a = (Author) all[0];
String name = a.name();
int year = a.year();
System.out.println("name:" + name + ", year:" + year);
//name:jack, year:2017
}
}
常见的字节码操作类库
- BCEL(Byte Code Engineering Library)
- ASM
- CGLIB(Code Generation Library)
- javassist