Java学习之javassist
ClassPool pool = ClassPool.getDefault();
//会从classpath中查询该类
CtClass cc = pool.get("test.Rectangle");
//设置.Rectangle的父类
cc.setSuperclass(pool.get("test.Point"));
//输出.Rectangle.class文件到该目录中
cc.writeFile("c://");
//输出成二进制格式
//byte[] b=cc.toBytecode();
//输出并加载class 类,默认加载到当前线程的ClassLoader中,也可以选择输出的ClassLoader。
//Class clazz=cc.toClass();
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("Point");
//新增方法
cc.addMethod(m);
//新增Field
cc.addField(f);
CtClasss cc = ...;
:
cc.writeFile();
cc.defrost();
cc.setSuperclass(...); // OK since the class is not frozen.
CtClasss cc = ...;
cc.stopPruning(true);
:
cc.writeFile(); // convert to a class file.
// cc没有被释放
//默认加载方式如pool.insertClassPath(new ClassClassPath(this.getClass()));
ClassPool pool = ClassPool.getDefault();
//从file加载classpath
pool.insertClassPath("/usr/local/javalib")
//从URL中加载
ClassPath cp = new URLClassPath("www.javassist.org", , "/java/", "org.javassist.");
pool.insertClassPath(cp);
//从byte[] 中加载
byte[] b = a byte array;
String name = class name;
cp.insertClassPath(new ByteArrayClassPath(name, b));
//可以从输入流中加载class
InputStream ins = an input stream for reading a class file;
CtClass cc = cp.makeClass(ins);
CtClass cc = ... ;
cc.writeFile();
cc.detach();
//ClassPool(true) 会默认加载Jvm的ClassPath
ClassPool cp = new ClassPool(true);
// if needed, append an extra search path by appendClassPath()
ClassPool parent = ClassPool.getDefault();
ClassPool child = new ClassPool(parent);
child.insertClassPath("./classes");
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
cc.setName("Pair");
//重新在classpath加载
CtClass cc1 = pool.get("Point");
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("Point");
cc.writeFile(); // has frozened
//cc.setName("Pair"); wrong since writeFile() has been called.
CtClass cc2 = pool.getAndRename("Point", "Pair");
// 当Hello未加载的时候,下面是可以运行的。
ClassPool cp = ClassPool.getDefault();
CtClass cc = cp.get("Hello");
Class c = cc.toClass();
//下面这种情况,由于Hello2已加载,所以会出错
Hello2 h=new Hello2();
CtClass cc2 = cp.get("Hello2");
Class c2 = cc.toClass();//这里会抛出java.lang.LinkageError 异常
//解决加载问题,可以指定一个未加载的ClassLoader
Class c3 = cc.toClass(new MyClassLoader());
ClassPool pool = ClassPool.getDefault();
Loader cl = new Loader(pool);
CtClass ct = pool.get("test.Rectangle");
ct.setSuperclass(pool.get("test.Point"));
Class c = cl.loadClass("test.Rectangle");
Object rect = c.newInstance(); :
//Translator 为监听器
public class MyTranslator implements Translator {
void start(ClassPool pool)
throws NotFoundException, CannotCompileException {}
void onLoad(ClassPool pool, String classname)
throws NotFoundException, CannotCompileException
{
CtClass cc = pool.get(classname);
cc.setModifiers(Modifier.PUBLIC);
}
}
//示例
public class Main2 {
public static void main(String[] args) throws Throwable {
Translator t = new MyTranslator();
ClassPool pool = ClassPool.getDefault();
Loader cl = new Loader();
cl.addTranslator(pool, t);
cl.run("MyApp", args);
}
}
//输出
% 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. |
//实际方法
void move(int dx, int dy)
//javassist
CtMethod m = cc.getDeclaredMethod("move");
//打印dx,和dy
m.insertBefore("{ System.out.println($1); System.out.println($2); }");
//原方法
move(String a,String b)
move($$) 相当于move($,$)
如果新增一个方法,方法含有move的所有参数,则可以这些写:
exMove($$, context) 相当于 exMove($, $, context)
//原方法
int fact(int n) {
if (n <= )
return n;
else
return n * fact(n - );
}
//javassist调用
CtMethod cm = ...;
//这里代表使用了cflow
cm.useCflow("fact");
//这里用了cflow,说明当深度为0的时候,就是开始当第一次调用fact的方法的时候,打印方法的第一个参数
cm.insertBefore("if ($cflow(fact) == 0)"
+ " System.out.println(\"fact \" + $1);");
CtMethod m = ...;
CtClass etype = ClassPool.getDefault().get("java.io.IOException");
m.addCatch("{ System.out.println($e); throw $e; }", etype);
try {
the original method body
}
catch (java.io.IOException e) {
System.out.println(e);
throw e;
}
| $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. |
CtMethod cm = ... ;
cm.instrument(
new ExprEditor() {
public void edit(MethodCall m)
throws CannotCompileException
{
if (m.getClassName().equals("Point")
&& m.getMethodName().equals("move"))
m.replace("{ $1 = 0; $_ = $proceed($$); }");
}
});
| $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. |
CtClass point = ClassPool.getDefault().get("Point");
CtMethod m = CtNewMethod.make(
"public int xmove(int dx) { x += dx; }",
point);
point.addMethod(m);
在方法中调用其他方法,例如:
CtClass point = ClassPool.getDefault().get("Point");
CtMethod m = CtNewMethod.make(
"public int ymove(int dy) { $proceed(0, dy); }",
point, "this", "move");
其效果如下:
public int ymove(int dy) { this.move(, dy); }
CtClass cc = ... ;
CtMethod m = new CtMethod(CtClass.intType, "move",
new CtClass[] { CtClass.intType }, cc);
cc.addMethod(m);
m.setBody("{ x += $1; }");
cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT);
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().
CtClass cc = ... ;
CtMethod m = CtNewMethod.make("public abstract int m(int i);", cc);
CtMethod n = CtNewMethod.make("public abstract int n(int i);", cc);
cc.addMethod(m);
cc.addMethod(n);
m.setBody("{ return ($1 <= 0) ? 1 : (n($1 - 1) * $1); }");
n.setBody("{ return m($1); }");
cc.setModifiers(cc.getModifiers() & ~Modifier.ABSTRACT);
CtClass point = ClassPool.getDefault().get("Point");
CtField f = new CtField(CtClass.intType, "z", point);
point.addField(f);
//point.addField(f, "0"); // initial value is 0.
或者:
CtClass point = ClassPool.getDefault().get("Point");
CtField f = CtField.make("public int z = 0;", point);
point.addField(f);
调用removeField()或者removeMethod()。
//注解
public @interface Author {
String name();
int year();
}
//javassist代码
CtClass cc = ClassPool.getDefault().get("Point");
Object[] all = cc.getAnnotations();
Author a = (Author)all[];
String name = a.name();
int year = a.year();
System.out.println("name: " + name + ", year: " + year);
ClassPool pool = ClassPool.getDefault();
pool.importPackage("java.awt");
CtClass cc = pool.makeClass("Test");
CtField f = CtField.make("public Point p;", cc);
cc.addField(f);
package com.swust.javassist; import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod; public class Example1 {
public static void main(String[] args) throws Exception {
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.makeClass("bean.User"); //创建属性
CtField field01 = CtField.make("private int id;",cc);
CtField field02 = CtField.make("private String name;", cc);
cc.addField(field01);
cc.addField(field02); //创建方法
CtMethod method01 = CtMethod.make("public String getName(){return name;}", cc);
CtMethod method02 = CtMethod.make("public void setName(String name){this.name = name;}", cc);
cc.addMethod(method01);
cc.addMethod(method02); //添加有参构造器
CtConstructor constructor = new CtConstructor(new CtClass[]{CtClass.intType,pool.get("java.lang.String")},cc);
constructor.setBody("{this.id=id;this.name=name;}");
cc.addConstructor(constructor);
//无参构造器
CtConstructor cons = new CtConstructor(null,cc);
cons.setBody("{}");
cc.addConstructor(cons); cc.writeFile("E:/workspace/TestCompiler/src");
}
}
14.2 访问类实例变量
package com.swust.javassist; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Arrays; import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.Modifier; public class Example2 {
//获取类的简单信息
public static void test01() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.swust.beans.Person");
//得到字节码
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());//获取接口
System.out.println(cc.getMethods());//获取
}
//新生成一个方法
public static void test02() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.swust.beans.Person");
//第一种
//CtMethod cm = CtMethod.make("public String getName(){return name;}", cc);
//第二种
//参数:返回值类型,方法名,参数,对象
CtMethod cm = new CtMethod(CtClass.intType,"add",new CtClass[]{CtClass.intType,CtClass.intType},cc);
cm.setModifiers(Modifier.PUBLIC);//访问范围
cm.setBody("{return $1+$2;}");
//cc.removeMethod(m) 删除一个方法
cc.addMethod(cm);
//通过反射调用方法
Class clazz = cc.toClass();
Object obj = clazz.newInstance();//通过调用无参构造器,生成新的对象
Method m = clazz.getDeclaredMethod("add", int.class,int.class);
Object result = m.invoke(obj, ,);
System.out.println(result);
} //修改已有的方法
public static void test03() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("bean.User"); CtMethod cm = cc.getDeclaredMethod("hello",new CtClass[]{pool.get("java.lang.String")});
cm.insertBefore("System.out.println(\"调用前\");");//调用前
cm.insertAt(, "System.out.println(\"29\");");//行号
cm.insertAfter("System.out.println(\"调用后\");");//调用后 //通过反射调用方法
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Method m = clazz.getDeclaredMethod("hello", String.class);
Object result = m.invoke(obj, "张三");
System.out.println(result);
} //修改已有属性
public static void test04() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("bean.User"); //属性
CtField cf = new CtField(CtClass.intType,"age",cc);
cf.setModifiers(Modifier.PRIVATE);
cc.addField(cf);
//增加响应的get set方法
cc.addMethod(CtNewMethod.getter("getAge",cf));
cc.addMethod(CtNewMethod.setter("setAge",cf)); //访问属性
Class clazz = cc.toClass();
Object obj = clazz.newInstance();
Field field = clazz.getDeclaredField("age");
System.out.println(field);
Method m = clazz.getDeclaredMethod("setAge", int.class);
m.invoke(obj, );
Method m2 = clazz.getDeclaredMethod("getAge", null);
Object resutl = m2.invoke(obj,null);
System.out.println(resutl);
} //操作构造方法
public static void test05() throws Exception{
ClassPool pool = ClassPool.getDefault();
CtClass cc = pool.get("com.swust.beans.Person"); CtConstructor[] cons = cc.getConstructors();
for(CtConstructor con:cons){
System.out.println(con);
}
}
public static void main(String[] args) throws Exception {
test01();
//test02();
//test03();
//test04();
test05();
}
}
调用方法1获取类的基本信息,结果如下:
完整类名为:com.swust.beans.Person
类名为:Person
父类名称为:java.lang.Object
*****************************
*****************************
属性方法为:wait
属性方法为:wait
属性方法为:setName
属性方法为:notifyAll
属性方法为:wait
属性方法为:toString
属性方法为:getName
属性方法为:setAge
属性方法为:equals
属性方法为:main
属性方法为:getAge
属性方法为:getClass
属性方法为:clone
属性方法为:finalize
属性方法为:hashCode
属性方法为:notify
调用方法2添加新方法:
方法执行结果为:
这是在原有方法体执行之前增加的内容
张三
这是在原有方法体执行之后增加的内容
null
调用方法4修改已有属性:
增添的属性为:private int com.swust.beans.Person.age
getAge方法执行后的结果为:
增添的属性为:private int com.swust.beans.Person.height
getHeight方法执行后的结果为:
调用方法5操作构造函数:
javassist.CtConstructor@180cb01[public Person ()V]
Java学习之javassist的更多相关文章
- java 学习之路
一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133 http://i ...
- Java学习路线(转)
原文:http://www.hollischuang.com/archives/489 一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http ...
- 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...
- 0035 Java学习笔记-注解
什么是注解 注解可以看作类的第6大要素(成员变量.构造器.方法.代码块.内部类) 注解有点像修饰符,可以修饰一些程序要素:类.接口.变量.方法.局部变量等等 注解要和对应的配套工具(APT:Annot ...
- 分享篇——我的Java学习路线
虽然之前我是开发出身,但是我学习的语言是Objective-c,这个语言使用起来范围比较窄,对于自动化学习来说也是无用武之地,所以我自己学习了Java,对于一个有开发经验的人来说学习一门新语言相对来说 ...
- Java学习笔记(04)
Java学习笔记(04) 如有不对或不足的地方,请给出建议,谢谢! 一.对象 面向对象的核心:找合适的对象做合适的事情 面向对象的编程思想:尽可能的用计算机语言来描述现实生活中的事物 面向对象:侧重于 ...
- Java学习心得之 HttpClient的GET和POST请求
作者:枫雪庭 出处:http://www.cnblogs.com/FengXueTing-px/ 欢迎转载 Java学习心得之 HttpClient的GET和POST请求 1. 前言2. GET请求3 ...
- 0032 Java学习笔记-类加载机制-初步
JVM虚拟机 Java虚拟机有自己完善的硬件架构(处理器.堆栈.寄存器等)和指令系统 Java虚拟机是一种能运行Java bytecode的虚拟机 JVM并非专属于Java语言,只要生成的编译文件能匹 ...
- 0030 Java学习笔记-面向对象-垃圾回收、(强、软、弱、虚)引用
垃圾回收特点 垃圾:程序运行过程中,会为对象.数组等分配内存,运行过程中或结束后,这些对象可能就没用了,没有变量再指向它们,这时候,它们就成了垃圾,等着垃圾回收程序的回收再利用 Java的垃圾回收机制 ...
随机推荐
- JAVA NIO 真正做到处理一个事件
如下图所示: 组1:如果只有上面的红框,不能真正处理该事件,下次执行select()方法,仍然可以select出来该事件.出现死循环现象.如果只有下面的红框,下次select()结果为0,如果外层循环 ...
- Log4net 参数详解
<log4net> <!-- 错误日志类--> <logger name="logerror"> <level value="A ...
- uiwebview 播放视频
先吐槽下 昨天为了做一个链接优酷的视频难死我了 最后找到一个解决办法 就是uiwebview 播放视频,但是问题又出来了 怎么监听视频开始播放呢??? 我从百度着了4个小时 最后无功而返 最后我 ...
- Unicode解码、URL编码/解码
+ (NSString *) stringByReplaceUnicode:(NSString *)string { NSMutableString *convertedString = [strin ...
- Netty详解
Netty详解 http://blog.csdn.net/suifeng3051/article/category/2161821
- 解决Eclipse下第三方库无法导航源代码
写在前面(的废话):Eclipse无法导航代码,存在的可能性非常多,这里我们只讨论在引用第三方库时无法导航的情况,是一个很简单的Case,但是搜索能力好像不太及格,没找到一针见血的方案,于是自己研究了 ...
- @Html.ActionLink 添加样式 html标签
@Html.ActionLink(item.MessageTitle, "Detail", "News",new { MessageId = item.Mess ...
- ASP.NET自定义控件加载资源WebResource问题
最近项目用日期控件,想把My97的资源文件跟TextBox封装成一个DatePicker控件,其实很简单的意见事情,但是还是用了一天多的时间,主要的问题就是解决资源文件加载的问题.通过一天多的努力,得 ...
- SMO要点总结
SMO要点总结: SMO使用坐标上升的方法,求解SVM的最优解.和原始坐标上升方法的不同点在于: 1. 由于SVM的限制条件 ,所以不能只使用一个坐标,改为更新两个 2. 采用 ...
- aix5.1 5.2 5.3 6.1 7.1运维技术总结
++++++++++++++++++++++++++++ + Ruiy 20014-10 zz + +Technology Area; + Tel:150 55198367 + QQ:5160 591 ...