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的垃圾回收机制 ...
随机推荐
- 从头开始-05.C语言中函数
函数: 完成特定功能代码段 特点:函数只有调用的时候才会执行 定义格式:返回值类型 函数名称(形参类型 形参名称,...){ 语句; ... } 函数参数 形式参数:在定义函数的时候,函数名后面小括 ...
- ViewState存储到服务器
把viewstate保存在服务器上 将ViewState持久化保持在服务器端的代码,这样ViewState不占用网络带宽,因此其存取只是服务器的磁盘读取时间.并且它很小,可以说是磁盘随便转一圈就能同时 ...
- Oracle触发器Trigger基础1
/* Trigger是作用在表上,或是数据库上,或是用户上.当用户在表上(其他)做某些操作时,trigger将会自己执行. 可以在表上:insert,update,delete Trigger只对表的 ...
- Oracle Semaphore Management in UNIX Administration
Oracle UNIX/Linux Tips by Burleson Consulting Semaphores and Oracle 11g 信号量和数据库 Semaphores are data ...
- 解決 IE10 浏览器无法使用 ASP.NET From 验证登录的问题
最近应项目用到ASP.Net表单验证机制(FormsAuthentication),来判断用户是否已经登录,一切测试顺利,最后发布到IIS中后在IE10测试是发现始终判断用户没登录(其他浏览器一切正常 ...
- (转)DataTable添加行出现“该行已经属于另一个表”的错误!
1 DataTable dt1 = new DataTable(); DataTable dt2 = new DataTable(); //为dt1创建结构 DataColumn pName = ne ...
- Java多线程并发编程之原子变量与非阻塞同步机制
1.非阻塞算法 非阻塞算法属于并发算法,它们可以安全地派生它们的线程,不通过锁定派生,而是通过低级的原子性的硬件原生形式 -- 例如比较和交换.非阻塞算法的设计与实现极为困难,但是它们能够提供更好的吞 ...
- mysql 批量更新
bs_user 表,我们叫他 bu表, 字段user_id,len_id, think_wellUser 表,我们简称为tw表,中的user_id ,len_id 其中tw表的user_id 是bu表 ...
- ThinkPHP框架研究之一 基本函数 M和D的区别
http://my.oschina.net/wxweven/blog/56563?fromerr=32n4Nf7V https://segmentfault.com/q/101000000298807 ...
- Java 中使用Jackson反序列化
Build.gradle: compile group: 'org.codehaus.jackson', name: 'jackson-mapper-lgpl', version: '1.9.13' ...