使用实例
HelloWorld
package com.woate.learn; import org.objectweb.asm.Opcodes;
import cn.wensiqun.asmsupport.block.method.common.StaticMethodBody; import cn.wensiqun.asmsupport.clazz.AClass; import cn.wensiqun.asmsupport.clazz.AClassFactory; import cn.wensiqun.asmsupport.creator.ClassCreator; import cn.wensiqun.asmsupport.creator.IClassContext; import cn.wensiqun.asmsupport.definition.value.Value; import cn.wensiqun.asmsupport.definition.variable.GlobalVariable; import cn.wensiqun.asmsupport.definition.variable.LocalVariable;
public class HelloWorld {
public static void main(String[] args) { ClassCreator creator = new ClassCreator(Opcodes.V1_5, Opcodes.ACC_PUBLIC, "generated.helloworld.HelloWorldExample", null, null); creator.createStaticMethod("main", new AClass[] { AClassFactory.getProductClass(String[].class) }, new String[] { "args" }, null, null, Opcodes.ACC_PUBLIC + Opcodes.ACC_STATIC, new StaticMethodBody() {
@Override public void body(LocalVariable... argus) { invoke(systemOut, "println", Value.value("Hello World")); // don't forget return. runReturn(); }
}); generate(creator); }
public static GlobalVariable systemOut = AClassFactory.getProductClass(System.class).getGlobalVariable("out");
public static Class<?> generate(IClassContext creator) { // _这是Class的输出路径。主要为了调试作用。我们通过asmsupport生成的class将获输出到这个路径 // 你可以通过反编译软件看看我们生成的结果 creator.setClassOutPutPath(".//target//");
// 这个就是个开关。前面我们把该创建的方法变量都放到了传送带上了。调用startup // 启动传送带,将上面的东西一个个处理给我返回一个我们需要的成品(就是class了) Class<?> cls = creator.startup();
try { cls.getMethod("main", String[].class).invoke(cls, new Object[] { null }); } catch (Exception e) { e.printStackTrace(); } return cls; }
}
|
creator.setClassOutPutPath(".//target//");用于设置字节码生成的根目录。会在根目录根据包名创建文件层次路径。
creator.startup();启动生成字节码过程。
生成接口
生成一个空接口,通常适用于标记的接口
/** * 创建一个空的接口,没有任何方法,也无任何成员,继承克隆接口 */ public void testCreateBlankInterface(){ InterfaceCreator creator = new InterfaceCreator(Opcodes.V1_6, "generated.create.CreateBlankInterface", new Class[]{Cloneable.class}); creator.setClassOutPutPath(".//target//"); creator.startup(); } |
接口创建使用InterfaceCreator,它是AbstractClassCreatorContext的子类,与ClassCreator一样是其子类。
jdk version :JDK的版本。可以用过org.objectweb.asm.Opcodes获取,比如:Opcodes.V1_5表示1.5版本的jdk
class modifiers : 表示创建的Class的修饰符。修饰符同样也是通过org.objectweb.asm.Opcodes获取,比如修饰符是"public abstract"则是 Opcodes.ACC_PUBLIC + Opcodes.ACC_ABSTRACT
the class full name : Class的全名。比如:asmsupport.oschina.TestClass super class。 : 当前创建的class的父类,如果为null则是继承自Object.class。参数类型是class
interfaces : 实现了那些接口,可以是null,类型是Class[]
生成一个有变量的接口
/** * 创建一个空的接口,没有任何方法,也无任何成员 */ public void testCreateVarInterface(){ InterfaceCreator creator = new InterfaceCreator(Opcodes.V1_6, "generated.create.CreateVarInterface", null); //创建一个全局变量,实际是常量,未赋值,那么实际就是null creator.createGlobalVariable("globalValue1", AClass.STRING_ACLASS); //创建一个全局变量,实际是常量 creator.createGlobalVariable("globalValue2", AClass.STRING_ACLASS); creator.createGlobalVariable("globalValue3", AClass.INT_ACLASS); //使用静态代码块对全局变量globalValue2赋值 creator.createStaticBlock(new ClinitBody() { @Override public void body() { //绑定值字符串到globalValue2 assign(getMethodOwner().getGlobalVariable("globalValue2"), Value.value("I'm a global variable at Interface")); //绑定值数字到globalValue3 assign(getMethodOwner().getGlobalVariable("globalValue3"), Value.value(5)); runReturn(); } }); creator.setClassOutPutPath(".//target//"); creator.startup(); } |
接口中创建的变量需要在静态代码块进行绑定值初始化
字面量可以使用Value.value(字面量值)构建出Parameterized实例。
一个块结束是需要调用return语句。如果无返回值,则调用runReturn();如果有返回值,则调用runReturn(Parameterized)返回值。
getMethodOwner().getGlobalVariable(变量名)可获取接口或者类中定义的全局变量。
assign(ExplicitVariable, Parameterized)可以实现对全局变量的绑定赋值。
注意:全局变量和代码块定义顺序无关。也就是creator.createGlobalVariable("globalValue3", AClass.INT_ACLASS);和creator.createStaticBlock(new ClinitBody() {...});方法调用可以交换。
Value.value(字面量值)目前支持的类型有
1.Integer
2.Short
3.Byte
4.Boolean
5.Long
6.Double
7.Character
8.Float
9.String
10.AClass
11.Class
生成一个有方法的接口
/** * 创建一个接口,有方法method1,方法返回值String,方法输入字节,整数 */ public void testCreateMethodInterface(){ InterfaceCreator creator = new InterfaceCreator(Opcodes.V1_6, "generated.create.CreateMethodInterface", null); creator.createMethod("method1", new AClass[]{AClass.BYTE_ACLASS, AClass.INT_ACLASS}, AClass.STRING_ACLASS, new AClass[]{AClassFactory.getProductClass(IOException.class)}); creator.setClassOutPutPath(".//target//"); creator.startup(); } |
InterfaceCreator.createMethod()用于创建方法。输入参数为第二个参数AClass数组,按数组顺序描述方法参数输入的顺序。第三个参数AClass,定义了方法的返回类型。第四个参数AClass数组,描述了异常列表。
生成一个有内部类的接口,目前此框架不支持
|
生成枚举
生成一个没有任何值的枚举
目前框架不支持
生成一个只有常量值的枚举
/** * 生成一个只有常量值的枚举 */ @Test public void testCreateConstantEnum(){ EnumCreator creator = new EnumCreator(Opcodes.V1_6, "generated.create.CreateConstantEnum", null); creator.createEnumConstant("Monday"); creator.setClassOutPutPath(".//target//"); creator.startup(); } |
生成一个只有常量值的枚举,同时使用构造器进行初始化
目前框架不支持