利用ASM和Javassist动态生成Class 类(set和get)

利用jvm的指令集直接构造class,简单的bean class 还是有应用场景的。在此利用ASM和Javassist各造例子以备忘!

抽象类:SimpleJbean

public abstract class SimpleJbean {  
    public abstract byte[] createBeanClass(String className, List<FieldInfo> fields);  
}  

ASM实现:

import java.util.List;  
  
import org.apache.commons.lang.StringUtils;  
import org.objectweb.asm.ClassWriter;  
import org.objectweb.asm.MethodVisitor;  
import org.objectweb.asm.Opcodes;  
import org.objectweb.asm.Type;  
  
import com.FieldInfo;  
import com.SimpleJbean;  
  
/** 
 * SimpleJbean.java. 2011-12-28下午4:12:18 @author LionBule. 
 */  
public class SimpleJbeanAsm extends SimpleJbean implements Opcodes {  
  
    @Override  
    public byte[] createBeanClass(String className, List<FieldInfo> fields) {  
        ClassWriter cw = new ClassWriter(0);  
  
        cw.visit(V1_1, ACC_PUBLIC, className, null, "java/lang/Object", null);  
  
        // creates a MethodWriter for the (implicit) constructor  
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);  
        mv.visitVarInsn(ALOAD, 0);  
        mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");  
        mv.visitInsn(RETURN);  
        mv.visitMaxs(1, 1);  
  
        // create set&get methods  
        for (FieldInfo f : fields) {  
            addMethod(cw, mv, className, f);  
        }  
  
        return cw.toByteArray();  
    }  
  
    private void addMethod(ClassWriter cw, MethodVisitor mv, String className,  
                                  FieldInfo fieldInfo) {  
        String fieldName = fieldInfo.name;  
        String setMethodName = "set" + StringUtils.capitalize(fieldName);  
        String getMethodName = "get" + StringUtils.capitalize(fieldName);  
  
        String typeof = Type.getType(fieldInfo.type).getDescriptor();  
        String getof = getof(typeof);  
        String setof = setof(typeof);  
        int[] loadAndReturnOf = loadAndReturnOf(typeof);  
          
        //add field  
        cw.visitField(ACC_PRIVATE, fieldName, typeof, null, 0).visitEnd();  
  
        // getMethod  
        mv = cw.visitMethod(ACC_PUBLIC, getMethodName, getof, null, null);  
        mv.visitCode();  
        mv.visitVarInsn(ALOAD, 0);  
        mv.visitFieldInsn(GETFIELD, className, fieldName, typeof);  
        mv.visitInsn(loadAndReturnOf[1]);  
        mv.visitMaxs(2, 1);  
        mv.visitEnd();  
          
        // setMethod  
        mv = cw.visitMethod(ACC_PUBLIC, setMethodName, setof, null, null);  
        mv.visitCode();  
        mv.visitVarInsn(ALOAD, 0);  
        mv.visitVarInsn(loadAndReturnOf[0], 1);  
        mv.visitFieldInsn(PUTFIELD, className, fieldName, typeof);  
        mv.visitInsn(RETURN);  
        mv.visitMaxs(3, 3);  
        mv.visitEnd();  
    }  
  
    private String setof(String typeof) {  
        return "(" + typeof + ")V";  
    }  
  
    private String getof(String typeof) {  
        return "()" + typeof;  
    }  
      
    private int[] loadAndReturnOf(String typeof) {  
        if (typeof.equals("I") || typeof.equals("Z")) {  
            return new int[]{ILOAD,IRETURN};  
        } else if (typeof.equals("J")) {  
            return new int[]{LLOAD,LRETURN};  
        } else if (typeof.equals("D")) {  
            return new int[]{DLOAD,DRETURN};  
        } else if (typeof.equals("F")) {  
            return new int[]{FLOAD,FRETURN};  
        } else {  
            return new int[]{ALOAD,ARETURN};  
        }  
    }  
  
}  

Javassist实现:

import java.util.List;  
  
import org.apache.commons.lang.StringUtils;  
  
import com.FieldInfo;  
import com.SimpleJbean;  
  
import javassist.ClassPool;  
import javassist.CtClass;  
import javassist.CtField;  
import javassist.CtMethod;  
import javassist.CtNewMethod;  
  
/** 
 * JbeanUtil.java. 2011-12-26下午4:05:02 @author LionBule. 
 */  
public class SimpleJbeanJs extends SimpleJbean {  
    private final static String SETTER_STR    = "set";  
    private final static String GETTER_STR    = "get";  
    // type/fieldName  
    private final static String fieldTemplate = "private %s %s;";  
  
    @Override  
    public byte[] createBeanClass(String className, List<FieldInfo> fields){  
        try{  
            ClassPool cpool = ClassPool.getDefault();  
            CtClass cc = cpool.makeClass(StringUtils.capitalize(className));  
  
            String setMethodName = null;  
            String getMethodName = null;  
  
            for (FieldInfo fi : fields) {  
                setMethodName = SETTER_STR + StringUtils.capitalize(fi.name);  
                getMethodName = GETTER_STR + StringUtils.capitalize(fi.name);  
  
                CtField newField = CtField.make(String.format(fieldTemplate, fi.type.getName(), fi.name), cc);  
                cc.addField(newField);  
  
                CtMethod ageSetter = CtNewMethod.setter(setMethodName, newField);  
                cc.addMethod(ageSetter);  
                CtMethod ageGetter = CtNewMethod.getter(getMethodName, newField);  
                cc.addMethod(ageGetter);  
            }  
  
            return cc.toBytecode();  
        }catch(Exception e){  
            throw new RuntimeException(e);  
        }  
  
    }  
  
}  

单元测试:

import static org.junit.Assert.*;  
  
import java.lang.reflect.Method;  
import java.util.ArrayList;  
import java.util.List;  
  
import org.apache.commons.lang.StringUtils;  
import org.junit.Before;  
import org.junit.Test;  
  
import com.asm.util.SimpleJbeanAsm;  
import com.javassist.util.SimpleJbeanJs;  
  
/** 
 * SimpleJbeanTest.java. 2011-12-30下午9:00:09 @author LionBule. 
 */  
public class SimpleJbeanTest extends ClassLoader {  
    private String          className;  
    private List<FieldInfo> fields;  
  
    @Before  
    public void setUp() throws Exception {  
        className = "User";  
        FieldInfo testString = new TestFieldInfo(String.class, "name", "lionbule");  
        FieldInfo testInt = new TestFieldInfo(int.class, "age", 27);  
        FieldInfo testLong = new TestFieldInfo(long.class, "count", 9999999999L);  
        FieldInfo testFloat = new TestFieldInfo(float.class, "score", 89.312F);  
        FieldInfo testDouble = new TestFieldInfo(double.class, "number", 89.3121313D);  
        FieldInfo testBoolean = new TestFieldInfo(Boolean.class, "isStudent", false);  
  
        fields = new ArrayList<FieldInfo>();  
        fields.add(testString);  
        fields.add(testInt);  
        fields.add(testLong);  
        fields.add(testFloat);  
        fields.add(testDouble);  
        fields.add(testBoolean);  
    }  
  
    @Test  
    public void testSimpleJbeanJs() {  
        try {  
            SimpleJbean simpleJbean = new SimpleJbeanJs();  
            doAction(simpleJbean);  
        } catch (Exception e) {  
            e.printStackTrace();  
            fail(e.getMessage());  
        }  
  
    }  
  
    @Test  
    public void testSimpleJbeanAsm() {  
        try {  
            SimpleJbean simpleJbean = new SimpleJbeanAsm();  
            doAction(simpleJbean);  
        } catch (Exception e) {  
            e.printStackTrace();  
            fail(e.getMessage());  
        }  
  
    }  
  
    private void doAction(SimpleJbean simpleJbean) throws Exception {  
        byte[] classBytes = simpleJbean.createBeanClass(className, fields);  
  
        Class<?> userClass = this.defineClass(className, classBytes, 0, classBytes.length);  
  
        //invoker  
        Object user = userClass.newInstance();  
        TestFieldInfo tempField = null;  
        for (FieldInfo t : fields) {  
            tempField = (TestFieldInfo) t;  
  
            String setMethodName = "set" + StringUtils.capitalize(tempField.name);  
            String getMethodName = "get" + StringUtils.capitalize(tempField.name);  
  
            Method setMethod = userClass.getMethod(setMethodName, new Class[] { tempField.type });  
            setMethod.invoke(user, new Object[] { tempField.value });  
            Method getMethod = userClass.getMethod(getMethodName, new Class[] {});  
            System.out.println(getMethod.toGenericString());  
            Object result = getMethod.invoke(user, new Object[] {});  
            assertEquals(tempField.value, result);  
        }  
  
    }  
      
}  

FieldInfo

public class FieldInfo {

    public String name;
    public Class<?> type;

    public FieldInfo(Class<?> type, String name) {
        this.type = type;
        this.name = name;

    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Class<?> getType() {
        return type;
    }

    public  void setType(Class<?> type) {
        this.type = type;
    }

}


public class TestFieldInfo extends FieldInfo {
    public Object value;

    public TestFieldInfo(Class<?> type, String name, Object value) {
        super(type, name);
        this.value = value;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值