利用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);
        }

    }
    
}
 

ASM和Javassist的区别和侧重点,google下有很多资料,不再详述。

看了上面列子也会有大概的感触!

 

源码地址:

http://lionbule-java-open.googlecode.com/svn/trunk/lionbule-compile

 

reference:

1. http://asm.ow2.org/doc/developer-guide.html

2. http://download.forge.objectweb.org/asm/asm4-guide.pdf

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值