ctMethod.insertBefore("com.profiler.core.JpProcessor.methodBegin($$);");
用法:方法返回前插入代碼:
ctMethod.insertAfter("com.profiler.core.JpProcessor.methodBegin(null);");
其它用法:insertParameter、addCatch、insertAt 等
public byte[] modifyBytecode(String className, byte[] originalBytecode, boolean profileArgs) {
try {
CtClass ctClass = ClassPool.getDefault().makeClass(new ByteArrayInputStream(originalBytecode));
CtMethod[] declaredMethods = ctClass.getDeclaredMethods();
for (CtMethod ctMethod : declaredMethods) {
try {
if (ctMethod.isEmpty()) continue;// abstract or method body is {}
MethodInfo methodInfo = ctMethod.getMethodInfo();
if (methodInfo.isConstructor()) continue;// name:<init>
if(methodInfo.isStaticInitializer()) continue;// <clinit>
// methodInfo.getAccessFlags(); // ACC_ABSTRACT/ACC_PUBLIC/ACC_FINAL etc.
if (methodInfo.isMethod()) {
System.out.println(methodInfo.getName());
int lineNumber = ctMethod.getMethodInfo().getLineNumber(0);
System.out.println("lineNumber:" + lineNumber);
ctMethod.insertBefore("com.profiler.core.JpProcessor.methodBegin($$);");
ctMethod.insertAfter("com.profiler.core.JpProcessor.methodBegin(null);");
}
} catch (Exception e) {
e.printStackTrace();
}
}
} catch (IOException e) {
e.printStackTrace();
}
return originalBytecode;// NOP
}
1 ClassPool pool = ClassPool.getDefault(); 2 //會從classpath中查詢該類 3 CtClass cc = pool.get("test.Rectangle"); 4 //設置.Rectangle的父類 5 cc.setSuperclass(pool.get("test.Point")); 6 //輸出.Rectangle.class文件到該目錄中 7 cc.writeFile("c://"); 8 //輸出成二進制格式 9 //byte[] b=cc.toBytecode(); 10 //輸出並加載class 類,默認加載到當前線程的ClassLoader中,也可以選擇輸出的ClassLoader。 11 //Class clazz=cc.toClass();
1 ClassPool pool = ClassPool.getDefault(); 2 CtClass cc = pool.makeClass("Point"); 3 //新增方法 4 cc.addMethod(m); 5 //新增Field 6 cc.addField(f);
1 CtClasss cc = ...; 2 : 3 cc.writeFile(); 4 cc.defrost(); 5 cc.setSuperclass(...); // OK since the class is not frozen.
1 CtClasss cc = ...; 2 cc.stopPruning(true); 3 : 4 cc.writeFile(); // convert to a class file. 5 // cc沒有被釋放
1 //默認加載方式如pool.insertClassPath(new ClassClassPath(this.getClass())); 2 ClassPool pool = ClassPool.getDefault(); 3 //從file加載classpath 4 pool.insertClassPath("/usr/local/javalib") 5 //從URL中加載 6 ClassPath cp = new URLClassPath("www.javassist.org", 80, "/java/", "org.javassist."); 7 pool.insertClassPath(cp); 8 //從byte[] 中加載 9 byte[] b = a byte array; 10 String name = class name; 11 cp.insertClassPath(new ByteArrayClassPath(name, b)); 12 //可以從輸入流中加載class 13 InputStream ins = an input stream for reading a class file; 14 CtClass cc = cp.makeClass(ins);
1 CtClass cc = ... ; 2 cc.writeFile(); 3 cc.detach();
1 //ClassPool(true) 會默認加載Jvm的ClassPath 2 ClassPool cp = new ClassPool(true); 3 // if needed, append an extra search path by appendClassPath()
1 ClassPool parent = ClassPool.getDefault(); 2 ClassPool child = new ClassPool(parent); 3 child.insertClassPath("./classes");
1 ClassPool pool = ClassPool.getDefault(); 2 CtClass cc = pool.get("Point"); 3 cc.setName("Pair"); 4 //重新在classpath加載 5 CtClass cc1 = pool.get("Point");
1 ClassPool pool = ClassPool.getDefault(); 2 CtClass cc = pool.get("Point"); 3 cc.writeFile(); // has frozened 4 //cc.setName("Pair"); wrong since writeFile() has been called. 5 CtClass cc2 = pool.getAndRename("Point", "Pair");
1 // 當Hello未加載的時候,下面是可以運行的。 2 ClassPool cp = ClassPool.getDefault(); 3 CtClass cc = cp.get("Hello"); 4 Class c = cc.toClass(); 5 //下面這種情況,由於Hello2已加載,所以會出錯 6 Hello2 h=new Hello2(); 7 CtClass cc2 = cp.get("Hello2"); 8 Class c2 = cc.toClass();//這裏會拋出java.lang.LinkageError 異常 9 //解決加載問題,可以指定一個未加載的ClassLoader 10 Class c3 = cc.toClass(new MyClassLoader());
1 ClassPool pool = ClassPool.getDefault(); 2 Loader cl = new Loader(pool); 3 CtClass ct = pool.get("test.Rectangle"); 4 ct.setSuperclass(pool.get("test.Point")); 5 Class c = cl.loadClass("test.Rectangle"); 6 Object rect = c.newInstance(); :
1 //Translator 爲監聽器 2 public class MyTranslator implements Translator { 3 void start(ClassPool pool) 4 throws NotFoundException, CannotCompileException {} 5 void onLoad(ClassPool pool, String classname) 6 throws NotFoundException, CannotCompileException 7 { 8 CtClass cc = pool.get(classname); 9 cc.setModifiers(Modifier.PUBLIC); 10 } 11 } 12 //示例 13 public class Main2 { 14 public static void main(String[] args) throws Throwable { 15 Translator t = new MyTranslator(); 16 ClassPool pool = ClassPool.getDefault(); 17 Loader cl = new Loader(); 18 cl.addTranslator(pool, t); 19 cl.run("MyApp", args); 20 } 21 } 22 //輸出 23 % java Main2 arg1 arg2...
ClassPool pool = ClassPool.getDefault(); CtClass cc = pool.get("java.lang.String"); CtField f = new CtField(CtClass.intType, "hiddenValue", cc); f.setModifiers(Modifier.PUBLIC); cc.addField(f); cc.writeFile("."); //運行腳本 % java -Xbootclasspath/p:. MyApp arg1 arg2...
$0, $1, $2, ... | this and actual parameters |
$args | An array of parameters. The type of $args is Object[]. |
$$ | All actual parameters.For example, m($$) is equivalent to m($1,$2,...) |
$cflow(...) | cflow variable |
$r | The result type. It is used in a cast expression. |
$w | The wrapper type. It is used in a cast expression. |
$_ | The resulting value |
$sig | An array of java.lang.Class objects representing the formal parameter types |
$type | A java.lang.Class object representing the formal result type. |
$class | A java.lang.Class object representing the class currently edited. |
1 //實際方法 2 void move(int dx, int dy) 3 //javassist 4 CtMethod m = cc.getDeclaredMethod("move"); 5 //打印dx,和dy 6 m.insertBefore("{ System.out.println($1); System.out.println($2); }");
1 //原方法 2 move(String a,String b) 3 move($$) 相當於move($1,$2) 4 如果新增一個方法,方法含有move的所有參數,則可以這些寫: 5 exMove($$, context) 相當於 exMove($1, $2, context)
1 //原方法 2 int fact(int n) { 3 if (n <= 1) 4 return n; 5 else 6 return n * fact(n - 1); 7 } 8 //javassist調用 9 CtMethod cm = ...; 10 //這裏代表使用了cflow 11 cm.useCflow("fact"); 12 //這裏用了cflow,說明當深度爲0的時候,就是開始當第一次調用fact的方法的時候,打印方法的第一個參數 13 cm.insertBefore("if ($cflow(fact) == 0)" 14 + " System.out.println(\"fact \" + $1);");
1 CtMethod m = ...; 2 CtClass etype = ClassPool.getDefault().get("java.io.IOException"); 3 m.addCatch("{ System.out.println($e); throw $e; }", etype);
1 try { 2 the original method body 3 } 4 catch (java.io.IOException e) { 5 System.out.println(e); 6 throw e; 7 }
$0, $1, $2, ... | this and actual parameters |
$args | An array of parameters. The type of $args is Object[]. |
$$ | All actual parameters.For example, m($$) is equivalent to m($1,$2,...) |
$cflow(...) | cflow variable |
$r | The result type. It is used in a cast expression. |
$w | The wrapper type. It is used in a cast expression. |
$sig | An array of java.lang.Class objects representing the formal parameter types |
$type | A java.lang.Class object representing the formal result type. |
$class | A java.lang.Class object representing the class currently edited. |
1 CtMethod cm = ... ; 2 cm.instrument( 3 new ExprEditor() { 4 public void edit(MethodCall m) 5 throws CannotCompileException 6 { 7 if (m.getClassName().equals("Point") 8 && m.getMethodName().equals("move")) 9 m.replace("{ $1 = 0; $_ = $proceed($$); }"); 10 } 11 });
$0 |
The target object of the method call. This is not equivalent to this, which represents the caller-side this object. $0 is null if the method is static. |
$1, $2, ... | The parameters of the method call. |
$_ | The resulting value of the method call. |
$r | The result type of the method call. |
$class | A java.lang.Class object representing the class declaring the method. |
$sig | An array of java.lang.Class objects representing the formal parameter types |
$type | A java.lang.Class object representing the formal result type. |
$proceed | The name of the method originally called in the expression. |
$0 | The target object of the constructor call. This is equivalent to this. |
$1, $2, ... | The parameters of the constructor call. |
$class | A java.lang.Class object representing the class declaring the constructor. |
$sig | An array of java.lang.Class objects representing the formal parameter types. |
$proceed | The name of the constructor originally called in the expression. |
$0 |
The object containing the field accessed by the expression. This is not equivalent to this. this represents the object that the method including the expression is invoked on. $0 is null if the field is static. |
$1 |
The value that would be stored in the field if the expression is write access. Otherwise, $1 is not available. |
$_ |
The resulting value of the field access if the expression is read access. Otherwise, the value stored in $_ is discarded. |
$r |
The type of the field if the expression is read access. Otherwise, $r is void. |
$class | A java.lang.Class object representing the class declaring the field. |
$type | A java.lang.Class object representing the field type. |
$proceed | The name of a virtual method executing the original field access. . |
$0 | null |
$1, $2, ... | The parameters to the constructor. |
$_ |
The resulting value of the object creation. A newly created object must be stored in this variable. |
$r | The type of the created object. |
$sig | An array of java.lang.Class objects representing the formal parameter types |
$type | A java.lang.Class object representing the class of the created object. |
$proceed | The name of a virtual method executing the original object creation. . |
$0 | null |
$1, $2, ... | The size of each dimension. |
$_ |
The resulting value of the object creation. A newly created array must be stored in this variable. |
$r | The type of the created object. |
$type | A java.lang.Class object representing the class of the created array . |
$proceed | The name of a virtual method executing the original array creation. . |
$0 | null |
$1 | The value on the left hand side of the original instanceof operator. |
$_ | The resulting value of the expression. The type of $_ is boolean. |
$r | The type on the right hand side of the instanceof operator. |
$type | A java.lang.Class object representing the type on the right hand side of the instanceof operator. |
$proceed |
The name of a virtual method executing the original instanceof expression. It takes one parameter (the type is java.lang.Object) and returns true if the parameter value is an instance of the type on the right hand side of the original instanceof operator. Otherwise, it returns false. |
$0 | null |
$1 | The value the type of which is explicitly cast. |
$_ |
The resulting value of the expression. The type of $_ is the same as the type after the explicit casting, that is, the type surrounded by ( ). |
$r | the type after the explicit casting, or the type surrounded by ( ). |
$type | A java.lang.Class object representing the same type as $r. |
$proceed |
The name of a virtual method executing the original type casting. It takes one parameter of the type java.lang.Object and returns it after the explicit type casting specified by the original expression. |
$1 | The exception object caught by the catch clause. |
$r | the type of the exception caught by the catch clause. It is used in a cast expression. |
$w | The wrapper type. It is used in a cast expression. |
$type |
A java.lang.Class object representing the type of the exception caught by the catch clause. |
1 CtClass point = ClassPool.getDefault().get("Point"); 2 CtMethod m = CtNewMethod.make( 3 "public int xmove(int dx) { x += dx; }", 4 point); 5 point.addMethod(m); 6 7 在方法中調用其他方法,例如: 8 CtClass point = ClassPool.getDefault().get("Point"); 9 CtMethod m = CtNewMethod.make( 10 "public int ymove(int dy) { $proceed(0, dy); }", 11 point, "this", "move"); 12 其效果如下: 13 public int ymove(int dy) { this.move(0, dy); }
1 CtClass cc = ... ; 2 CtMethod m = new CtMethod(CtClass.intType, "move", 3 new CtClass[] { CtClass.intType }, cc); 4 cc.addMethod(m); 5 m.setBody("{ x += $1; }"); 6 cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT); 7 Since Javassist makes a class abstract if an abstract method is added to the class, you have to explicitly change the class back to a non-abstract one after calling setBody().
1 CtClass cc = ... ; 2 CtMethod m = CtNewMethod.make("public abstract int m(int i);", cc); 3 CtMethod n = CtNewMethod.make("public abstract int n(int i);", cc); 4 cc.addMethod(m); 5 cc.addMethod(n); 6 m.setBody("{ return ($1 <= 0) ? 1 : (n($1 - 1) * $1); }"); 7 n.setBody("{ return m($1); }"); 8 cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT);
1 CtClass point = ClassPool.getDefault().get("Point"); 2 CtField f = new CtField(CtClass.intType, "z", point); 3 point.addField(f); 4 //point.addField(f, "0"); // initial value is 0. 5 或者: 6 CtClass point = ClassPool.getDefault().get("Point"); 7 CtField f = CtField.make("public int z = 0;", point); 8 point.addField(f);
1 調用removeField()或者removeMethod()。
1 //註解 2 public @interface Author { 3 String name(); 4 int year(); 5 } 6 //javassist代碼 7 CtClass cc = ClassPool.getDefault().get("Point"); 8 Object[] all = cc.getAnnotations(); 9 Author a = (Author)all[0]; 10 String name = a.name(); 11 int year = a.year(); 12 System.out.println("name: " + name + ", year: " + year);
1 ClassPool pool = ClassPool.getDefault(); 2 pool.importPackage("java.awt"); 3 CtClass cc = pool.makeClass("Test"); 4 CtField f = CtField.make("public Point p;", cc); 5 cc.addField(f);
1 package com.swust.javassist; 2 3 import javassist.ClassPool; 4 import javassist.CtClass; 5 import javassist.CtConstructor; 6 import javassist.CtField; 7 import javassist.CtMethod; 8 9 public class Example1 { 10 public static void main(String[] args) throws Exception { 11 ClassPool pool = ClassPool.getDefault(); 12 CtClass cc = pool.makeClass("bean.User"); 13 14 //創建屬性 15 CtField field01 = CtField.make("private int id;",cc); 16 CtField field02 = CtField.make("private String name;", cc); 17 cc.addField(field01); 18 cc.addField(field02); 19 20 //創建方法 21 CtMethod method01 = CtMethod.make("public String getName(){return name;}", cc); 22 CtMethod method02 = CtMethod.make("public void setName(String name){this.name = name;}", cc); 23 cc.addMethod(method01); 24 cc.addMethod(method02); 25 26 //添加有參構造器 27 CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType,pool.get("java.lang.String")},cc); 28 constructor.setBody("{this.id=id;this.name=name;}"); 29 cc.addConstructor(constructor); 30 //無參構造器 31 CtConstructor cons = new CtConstructor(null,cc); 32 cons.setBody("{}"); 33 cc.addConstructor(cons); 34 35 cc.writeFile("E:/workspace/TestCompiler/src"); 36 } 37 }
14.2 訪問類實例變量
1 package com.swust.javassist; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Method; 5 import java.util.Arrays; 6 7 import javassist.ClassPool; 8 import javassist.CtClass; 9 import javassist.CtConstructor; 10 import javassist.CtField; 11 import javassist.CtMethod; 12 import javassist.CtNewMethod; 13 import javassist.Modifier; 14 15 public class Example2 { 16 //獲取類的簡單信息 17 public static void test01() throws Exception{ 18 ClassPool pool = ClassPool.getDefault(); 19 CtClass cc = pool.get("com.swust.beans.Person"); 20 //得到字節碼 21 byte[] bytes = cc.toBytecode(); 22 System.out.println(Arrays.toString(bytes)); 23 System.out.println(cc.getName());//獲取類名 24 System.out.println(cc.getSimpleName());//獲取簡要類名 25 System.out.println(cc.getSuperclass());//獲取父類 26 System.out.println(cc.getInterfaces());//獲取接口 27 System.out.println(cc.getMethods());//獲取 28 } 29 //新生成一個方法 30 public static void test02() throws Exception{ 31 ClassPool pool = ClassPool.getDefault(); 32 CtClass cc = pool.get("com.swust.beans.Person"); 33 //第一種 34 //CtMethod cm = CtMethod.make("public String getName(){return name;}", cc); 35 //第二種 36 //參數:返回值類型,方法名,參數,對象 37 CtMethod cm = new CtMethod(CtClass.intType,"add",new CtClass[]{CtClass.intType,CtClass.intType},cc); 38 cm.setModifiers(Modifier.PUBLIC);//訪問範圍 39 cm.setBody("{return $1+$2;}"); 40 //cc.removeMethod(m) 刪除一個方法 41 cc.addMethod(cm); 42 //通過反射調用方法 43 Class clazz = cc.toClass(); 44 Object obj = clazz.newInstance();//通過調用無參構造器,生成新的對象 45 Method m = clazz.getDeclaredMethod("add", int.class,int.class); 46 Object result = m.invoke(obj, 2,3); 47 System.out.println(result); 48 } 49 50 //修改已有的方法 51 public static void test03() throws Exception{ 52 ClassPool pool = ClassPool.getDefault(); 53 CtClass cc = pool.get("bean.User"); 54 55 CtMethod cm = cc.getDeclaredMethod("hello",new CtClass[]{pool.get("java.lang.String")}); 56 cm.insertBefore("System.out.println(\"調用前\");");//調用前 57 cm.insertAt(29, "System.out.println(\"29\");");//行號 58 cm.insertAfter("System.out.println(\"調用後\");");//調用後 59 60 //通過反射調用方法 61 Class clazz = cc.toClass(); 62 Object obj = clazz.newInstance(); 63 Method m = clazz.getDeclaredMethod("hello", String.class); 64 Object result = m.invoke(obj, "張三"); 65 System.out.println(result); 66 } 67 68 //修改已有屬性 69 public static void test04() throws Exception{ 70 ClassPool pool = ClassPool.getDefault(); 71 CtClass cc = pool.get("bean.User"); 72 73 //屬性 74 CtField cf = new CtField(CtClass.intType,"age",cc); 75 cf.setModifiers(Modifier.PRIVATE); 76 cc.addField(cf); 77 //增加響應的get set方法 78 cc.addMethod(CtNewMethod.getter("getAge",cf)); 79 cc.addMethod(CtNewMethod.setter("setAge",cf)); 80 81 //訪問屬性 82 Class clazz = cc.toClass(); 83 Object obj = clazz.newInstance(); 84 Field field = clazz.getDeclaredField("age"); 85 System.out.println(field); 86 Method m = clazz.getDeclaredMethod("setAge", int.class); 87 m.invoke(obj, 16); 88 Method m2 = clazz.getDeclaredMethod("getAge", null); 89 Object resutl = m2.invoke(obj,null); 90 System.out.println(resutl); 91 } 92 93 //操作構造方法 94 public static void test05() throws Exception{ 95 ClassPool pool = ClassPool.getDefault(); 96 CtClass cc = pool.get("com.swust.beans.Person"); 97 98 CtConstructor[] cons = cc.getConstructors(); 99 for(CtConstructor con:cons){ 100 System.out.println(con); 101 } 102 } 103 public static void main(String[] args) throws Exception { 104 test01(); 105 //test02(); 106 //test03(); 107 //test04(); 108 test05(); 109 } 110 }
調用方法1獲取類的基本信息,結果如下:
1 完整類名爲:com.swust.beans.Person 2 類名爲:Person 3 父類名稱爲:java.lang.Object 4 ***************************** 5 ***************************** 6 屬性方法爲:wait 7 屬性方法爲:wait 8 屬性方法爲:setName 9 屬性方法爲:notifyAll 10 屬性方法爲:wait 11 屬性方法爲:toString 12 屬性方法爲:getName 13 屬性方法爲:setAge 14 屬性方法爲:equals 15 屬性方法爲:main 16 屬性方法爲:getAge 17 屬性方法爲:getClass 18 屬性方法爲:clone 19 屬性方法爲:finalize 20 屬性方法爲:hashCode 21 屬性方法爲:notify
調用方法2添加新方法:
1 方法執行結果爲:5
1 這是在原有方法體執行之前增加的內容 2 張三 3 這是在原有方法體執行之後增加的內容 4 null
調用方法4修改已有屬性:
1 增添的屬性爲:private int com.swust.beans.Person.age 2 getAge方法執行後的結果爲:16 3 增添的屬性爲:private int com.swust.beans.Person.height 4 getHeight方法執行後的結果爲:176
調用方法5操作構造函數:
1 javassist.CtConstructor@180cb01[public Person ()V]