`

javassist【动态改字节码】学习三

    博客分类:
  • j2se
 
阅读更多
这里举个简单的例子,来记录下如何用CtClass创建一个类,并且往这个类里面新加方法,

下面是代码,可以直接运行:
Java代码

package seeeyou.app.test;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;

/**
*
* @author seeeyou
*
*/
public class TestHelloWorld2 {
public static void main(String[] args) throws NotFoundException,
IOException, CannotCompileException, InstantiationException,
IllegalAccessException, SecurityException, NoSuchMethodException,
IllegalArgumentException, InvocationTargetException {
// 用于取得字节码类,必须在当前的classpath中,使用全称
ClassPool pool = ClassPool.getDefault();
/**
* makeClass() cannot create a new interface; makeInterface() in
* ClassPool can do. Member methods in an interface can be created with
* abstractMethod() in CtNewMethod. Note that an interface method is an
* abstract method.
*/
CtClass ccClass = pool.makeClass("Point");
String bodyString = "{System.out.println(\"Call to method \");}";
//为新创建的类新加一个方法execute,无任何参数
CtMethod n1 = CtNewMethod.make(CtClass.voidType, "execute", null, null,
bodyString, ccClass);
ccClass.addMethod(n1);
/**
* 这里无法用new的形式来创建一个对象,因为已经classloader中不能有两个相同的对象,否则会报异常如下:
*Caused by: java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader):
*attempted  duplicate class definition for name: "Point"
**/
Object oo = ccClass.toClass().newInstance();
Method mms = oo.getClass().getMethod("execute", null);
System.out.println("new class name is : " + oo.getClass().getName());
System.out.println("new class's method is : " + mms.invoke(oo, null));
System.out.println("---------------------------------------------");
//这一行代码将class冻结了,下面无法再对类多编辑或者修改,下面的setName会报异常如:
//Exception in thread "main" java.lang.RuntimeException: Point class is frozen
ccClass.freeze();
try{
ccClass.setName("Point2");
}catch (Exception e) {
System.out.println(e);
}
//对已经冻结的class解冻之后还可以继续编辑修改
ccClass.defrost();
System.out.println("------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------");
//第二个方法
bodyString = "public int getNumber(Integer num){System.out.println(\"Point2 Call to method \");return 10+num;}";
CtMethod n2 = CtNewMethod.make(bodyString, ccClass);//直接创建一个方法,带有一个int的参数和返回值
ccClass.addMethod(n2);
Class[] params = new Class[1];
Integer num = new Integer(15);
params[0] = num.getClass();
mms = oo.getClass().getMethod("getNumber", params);
System.out.println("new class name is : " + oo.getClass().getName());
System.out.println("new class's method is : " + mms.invoke(oo, 100));
System.out.println("---------------------------------------------");
}
}

Java代码

上面的结果是:new class name is : Point
Call to method
new class's method is : null
---------------------------------------------
java.lang.RuntimeException: Point class is frozen
---------------------------------------------
Exception in thread "main" java.lang.NoSuchMethodException: Point.getNumber(java.lang.Integer)
at java.lang.Class.getMethod(Class.java:1605)
at seeeyou.app.test.TestHelloWorld2.main(TestHelloWorld2.java:66)



错误的原因其实和简单,因为我第二次新加一个方法后,没有再次实例化一个对象,所以oo还是原来的对象,他的成员函数肯定没有新加的方法。

那我可以再次实例化下试试,代码和结果如下:
Java代码

package seeeyou.app.test;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;

/**
*
* @author seeeyou
*
*/
public class TestHelloWorld2 {
public static void main(String[] args) throws NotFoundException,
IOException, CannotCompileException, InstantiationException,
IllegalAccessException, SecurityException, NoSuchMethodException,
IllegalArgumentException, InvocationTargetException {
// 用于取得字节码类,必须在当前的classpath中,使用全称
ClassPool pool = ClassPool.getDefault();
/**
* makeClass() cannot create a new interface; makeInterface() in
* ClassPool can do. Member methods in an interface can be created with
* abstractMethod() in CtNewMethod. Note that an interface method is an
* abstract method.
*/
CtClass ccClass = pool.makeClass("Point");
String bodyString = "{System.out.println(\"Call to method \");}";
//为新创建的类新加一个方法execute,无任何参数
CtMethod n1 = CtNewMethod.make(CtClass.voidType, "execute", null, null,
bodyString, ccClass);
ccClass.addMethod(n1);
/**
* 这里无法用new的形式来创建一个对象,因为已经classloader中不能有两个相同的对象,否则会报异常如下:
*Caused by: java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader):
*attempted  duplicate class definition for name: "Point"
**/
Object oo = ccClass.toClass().newInstance();
Method mms = oo.getClass().getMethod("execute", null);
System.out.println("new class name is : " + oo.getClass().getName());
System.out.println("new class's method is : " + mms.invoke(oo, null));
System.out.println("---------------------------------------------");
//这一行代码将class冻结了,下面无法再对类多编辑或者修改,下面的setName会报异常如:
//Exception in thread "main" java.lang.RuntimeException: Point class is frozen
ccClass.freeze();
try{
ccClass.setName("Point2");
}catch (Exception e) {
System.out.println(e);
}
//对已经冻结的class解冻之后还可以继续编辑修改
ccClass.defrost();
System.out.println("------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------");
//第二个方法
bodyString = "public int getNumber(Integer num){System.out.println(\"Point2 Call to method \");return 10+num;}";
CtMethod n2 = CtNewMethod.make(bodyString, ccClass);//直接创建一个方法,带有一个int的参数和返回值
ccClass.addMethod(n2);
Class[] params = new Class[1];
Integer num = new Integer(15);
params[0] = num.getClass();//就多了下面这个实例化,但是这样会导致一个错误
oo = ccClass.toClass().newInstance();
mms = oo.getClass().getMethod("getNumber", params);
System.out.println("new class name is : " + oo.getClass().getName());
System.out.println("new class's method is : " + mms.invoke(oo, 100));
System.out.println("---------------------------------------------");
}
}

Java代码

这也会导致一个错误:new class name is : Point
Call to method
new class's method is : null
---------------------------------------------
java.lang.RuntimeException: Point class is frozen
------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------
Exception in thread "main" javassist.CannotCompileException: by java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader): attempted  duplicate class definition for name: "Point"
at javassist.ClassPool.toClass(ClassPool.java:1051)
at javassist.ClassPool.toClass(ClassPool.java:994)
at javassist.ClassPool.toClass(ClassPool.java:952)
at javassist.CtClass.toClass(CtClass.java:1079)
at seeeyou.app.test.TestHelloWorld2.main(TestHelloWorld2.java:66)
Caused by: java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader): attempted  duplicate class definition for name: "Point"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
at java.lang.ClassLoader.defineClass(ClassLoader.java:466)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at javassist.ClassPool.toClass2(ClassPool.java:1063)
at javassist.ClassPool.toClass(ClassPool.java:1045)
... 4 more

Java代码

    原因也很简单,一个classloader里面怎么有两个重复的对象呢,除非是两个不同的classloader。。所以爆了个重复加载类的错误

原因也很简单,一个classloader里面怎么有两个重复的对象呢,除非是两个不同的classloader。。所以爆了个重复加载类的错误

Java代码



对的方式是只实例化一次:如下:
Java代码

package seeeyou.app.test;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import javassist.NotFoundException;

/**
*
* @author seeeyou
*
*/
public class TestHelloWorld3 {

public static void main(String[] args) throws NotFoundException,
IOException, CannotCompileException, InstantiationException,
IllegalAccessException, SecurityException, NoSuchMethodException,
IllegalArgumentException, InvocationTargetException {
// 用于取得字节码类,必须在当前的classpath中,使用全称
ClassPool pool = ClassPool.getDefault();
/**
* makeClass() cannot create a new interface; makeInterface() in
* ClassPool can do. Member methods in an interface can be created with
* abstractMethod() in CtNewMethod. Note that an interface method is an
* abstract method.
*/
CtClass ccClass = pool.makeClass("Point");
String bodyString = "{System.out.println(\"Call to method \");}";
//为新创建的类新加一个方法execute,无任何参数
CtMethod n1 = CtNewMethod.make(CtClass.voidType, "execute", null, null,
bodyString, ccClass);
ccClass.addMethod(n1);
//新加第二个方法
bodyString = "public Integer getNumber(Integer num);";
CtMethod n2 = CtNewMethod.make(bodyString, ccClass);//直接创建一个方法,带有一个int的参数和返回值
n2.setBody("{System.out.println(\"Point Call to method \");return $1;}");
ccClass.addMethod(n2);

/**
* 这里无法用new的形式来创建一个对象,因为已经classloader中不能有两个相同的对象,否则会报异常如下:
*Caused by: java.lang.LinkageError: loader (instance of  sun/misc/Launcher$AppClassLoader):
*attempted  duplicate class definition for name: "Point"
**/
Object oo = ccClass.toClass().newInstance();
Method mms = oo.getClass().getMethod("execute", null);
System.out.println("new class name is : " + oo.getClass().getName());
System.out.println("new class's method is : " + mms.invoke(oo, null));
System.out.println("---------------------------------------------");
//这一行代码将class冻结了,下面无法再对类多编辑或者修改,下面的setName会报异常如:
//Exception in thread "main" java.lang.RuntimeException: Point class is frozen
ccClass.freeze();
try{
ccClass.setName("Point2");
}catch (Exception e) {
System.out.println(e);
}
//对已经冻结的class解冻之后还可以继续编辑修改
ccClass.defrost();
System.out.println("------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------");
Class[] params = new Class[1];
Integer num = new Integer(0);
params[0] = num.getClass();
mms = oo.getClass().getMethod("getNumber",params);
System.out.println("new class name is : " + oo.getClass().getName());
System.out.println("new class's method is : " + mms.invoke(oo, 100));
System.out.println("---------------------------------------------");
}
}

Java代码

结果如下:new class name is : Point
Call to method
new class's method is : null
---------------------------------------------
java.lang.RuntimeException: Point class is frozen
------------- 上面的代码是对的,下面的代码将会无法执行出结果,会报错------------------------
new class name is : Point
Point2 Call to method
new class's method is : 100
---------------------------------------------

http://alicsd.com/a/226
分享到:
评论

相关推荐

    Javassist 修改class字节码

    Javassist 提供了java类库,用于方便操控Java字节码。功能包括:运行时创建java class,修改class。与其他同类工具(asm等)不同的是,Javassist提供了两个层面的API: 1.java代码层 2.字节码层 通过java代码层,...

    javassist, Java字节码工程工具包.zip

    javassist, Java字节码工程工具包 Java字节码工程工具包 版本 3版权所有( C ) 1999 -2017按 Shigeru Chiba,保留所有权利。Javassist ( Java编程助手) 使Java字节码操作简单。 它是一个类库,用于在Java中编辑字节码

    借助jclasslib与javassist修改java class字节码

    借助jclasslib与javassist修改java class字节码.doc

    javassist,Java字节码工程工具包.zip

    Java字节码工程工具包

    javassist试图简化Java字节码的编辑

    javassist:试图简化Java字节码的编辑

    Javassist如何操作Java 字节码

    主要介绍了Javassist如何操作Java 字节码,帮助大家更好的理解和学习Java,感兴趣的朋友可以了解下

    javassist:Java字节码工程工具包

    Javassist(JAVA编程ASSISTant)使Java字节码操作变得简单。 它是一个用Java编辑字节码的类库。 它使Java程序可以在运行时定义新类,并在JVM加载它时修改类文件。 与其他类似的字节码编辑器不同,Javassist提供了两...

    javassist-3.14.0-GA

    它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。 关于java字节码的处理,目前有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解...

    Javassistjar包

    它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。 关于java字节码的处理,目前有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解...

    javassist官方手册(中文)

    javassist是一个动态生成字节码的框架,生成的字节码可以输出或实时加载到jvm。文档内容全面。

    javassist反射工具

    它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。 关于java字节码的处理,目前有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解...

    免费开源!!Java字节码工程工具包

    Javassist(JAVA 编程助手)使 Java 字节码操作变得简单。它是Java中用于编辑字节码的类库;它使 Java 程序能够在运行时定义新类,并在 JVM 加载时修改类文件。与其他类似的字节码编辑器不同,Javassist 提供两个...

    javassist.zip

    Javassist(JAVA编程助手)进行JAVA字节码操作 易于理解的它是一个用于在Java中编辑字节码的类库;它支持Java 程序在运行时定义一个新类,并在 JVM加载它。与其他类似的字节码编辑器不同,Javassist提供了 API的...

    Javassist-3.12

    它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。 Javassist是一个执行字节码操作的强而有力的驱动代码库。它允许开发者自由的在一个已经编译好的类中添加新的方法...

    JavaAgent:Javassist 与 Asm JavaAgent 字节码动态编程项目

    JavaAgent Javassist 与 Asm JavaAgent 字节码动态编程项目

    javassist API chm格式

    javassist API chm格式 字节码生成类库

    javassist-3.18.0-ga.jar

    Javassist是一个开源的分析、编辑和创建Java字节码的类库。是由东京工业大学的数学和计算机科学系的 Shigeru ...它已加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态"AOP"框架。

    javassist-3.12.1.GA.jar

    开源的分析、编辑和创建Java字节码的类库,加入了开放源代码JBoss 应用服务器项目,通过使用Javassist对字节码操作为JBoss实现动态AOP框架。

    DroidAssist,一个基于javassist的轻量级android studio gradle插件,用于在android中编辑字节码。.zip

    机器人助手提供了一种更加轻量,简单易用,无侵入,可配置化的字节码操作方式,你不需要 Java 字节码的相关知识,只需要在 Xml 插件配置中添加简单的 Java 代码即可实现类似 AOP 的功能,同时不需要引入其他额外的...

Global site tag (gtag.js) - Google Analytics