Asm动态生成类和get and set方法

asm在解析文件的时候是按照特定顺序进行分析的,首先是visit方法,做类相关的解析,然后是注解,然后是属性,最后才是方法,属性是在所有方法分析前面进行,也就是只有当class文件中的所有属性都遍历完毕之后,才会去遍历方法

1.自定义类加载器

package club.jiajia.test;
public class MyClassLoader extends ClassLoader{  
    public  Class<?> defineClassByName(String name,byte[] b,int off,int len){   
        Class<?> clazz = super.defineClass(name,b, off, len);  
        return clazz;   
    }   
}

2.asm动态生成字节码

package club.jiajia.test2;
import java.util.List;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
/**
 * jiajiajia
 */
public class Asm implements Opcodes {
    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);
 
        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" +fieldName;
        String getMethodName = "get" +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};
        }
    }
}

3.定义属性信息

package club.jiajia.test2;

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

4.测试

package club.jiajia.test2;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import club.jiajia.test.MyClassLoader;
 
/**
 * jiajiajia
 */
public class Test extends ClassLoader {
    private static String className="Abc";
    private static List<FieldInfo> fields;
 
    public static byte[] setUp(){
        FieldInfo testString = new FieldInfo(int.class, "name", 1);
        testString.type="I";
        fields = new ArrayList<FieldInfo>();
        fields.add(testString);
        return  new Asm().createBeanClass(className, fields);
    }
    
    public static void main(String[] args) {
		byte b[]=setUp();
		MyClassLoader mcl=new MyClassLoader();  
        //返回的对象时被加载类的class  
        Class<?> hw=mcl.defineClassByName("Abc", b, 0, b.length);  
        try {  
            //利用反射创建对象  
            Object o= hw.newInstance();
            java.lang.reflect.Method method=   o.getClass().getMethod("getname");
            java.lang.reflect.Method method2=   o.getClass().getMethod("setname",int.class);
            method2.invoke(o,3);
            System.out.println(method.invoke(o));
        }catch (Exception e) {
        	e.printStackTrace();
		}
	    
		File file = new File("E://jiajiajia/Abc.class");
		try {
			FileOutputStream fout = new FileOutputStream(file);
			fout.write(b);
			fout.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}

5.测试结果

QQ截图20190305161048.png

测试的时候会在E://jiajiajia文件夹下生成一个Abc.clss文件

6.反编译结果为:

public class Abc
{
    private int name = 0;
    
    public int getname() {
        return this.name;
    }
    
    public void setname(final int name) {
        this.name = name;
    }
}

7.测试2

生成if条件判断

package club.jiajia.test3;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class TestAsm implements Opcodes{
	public static void main(String[] args) throws InstantiationException, IllegalAccessException{
		ClassWriter cw=new ClassWriter(0);
		String className="Example";
		cw.visit(0x31,ACC_PUBLIC,className,null,"java/lang/Object",new String[]{"java/lang/Cloneable",ITest.class.getName().replace('.','/')});

		String field="test";
		String a="a";
		Object defaultValue=123d;
		Object defaultValues=1123;
		String setMd="setTest";
		String getMd="getTest";
		
		String getMa="getMa";
		cw.visitField(ACC_PRIVATE,field,"D",null,defaultValue == null?null:Double.parseDouble(defaultValue.toString())).visitEnd();
		cw.visitField(ACC_PRIVATE,a,"I",null,defaultValues == null?null:Double.parseDouble(defaultValues.toString())).visitEnd();

		
		MethodVisitor mv=cw.visitMethod(ACC_PUBLIC,getMd,"()D",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		mv.visitFieldInsn(GETFIELD,className,field,"D");
		mv.visitInsn(DRETURN);
		mv.visitMaxs(2,2);
		mv.visitEnd();
		cw.visitEnd();
		
		
		

		mv=cw.visitMethod(ACC_PUBLIC,setMd,"(D)V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		/**
		 * 访问本地变量指令。本地变量指令是ar *指令,它加载或存储本地变量* @param的值。这个操作码是ILOAD, LLOAD, FLOAD, DLOAD, ALOAD, ISTORE, LSTORE, FSTORE, DSTORE, ASTORE或RET.* @param vanthe操作数的指令访问。这个操作数是一个局部变量的索引
		 */
		mv.visitVarInsn(DLOAD,1);
		mv.visitFieldInsn(PUTFIELD,className,field,"D");
		mv.visitInsn(RETURN);
		mv.visitMaxs(3,3);
		mv.visitEnd();
		
		
		
		
		/***********************************************************/
		mv=cw.visitMethod(ACC_PUBLIC,getMa,"(I)V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ILOAD, 1);
		Label label = new Label();
		mv.visitJumpInsn(IFLT, label);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ILOAD, 1);
		mv.visitFieldInsn(PUTFIELD, className, "a", "I");
		Label end = new Label();
		mv.visitJumpInsn(GOTO, end);
		mv.visitLabel(label);
		mv.visitFrame(F_SAME, 0, null, 0, null);
		mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
		mv.visitInsn(DUP);
		mv.visitMethodInsn(INVOKESPECIAL,
		"java/lang/IllegalArgumentException", "<init>", "()V");
		mv.visitInsn(ATHROW);
		mv.visitLabel(end);
		mv.visitFrame(F_SAME, 0, null, 0, null);
		mv.visitInsn(RETURN);
		mv.visitMaxs(2, 2);
		mv.visitEnd();
		/***********************************************************/
		
		
		
		//下面产生构造方法
		mv=cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		mv.visitMethodInsn(INVOKESPECIAL,"java/lang/Object","<init>","()V");
		mv.visitInsn(RETURN);
		mv.visitMaxs(1,1);
		mv.visitEnd();
		
		
		cw.visitEnd();

		byte[] bs=cw.toByteArray();
		File file = new File("E://jiajiajia/Example.class");
		try {
			FileOutputStream fout = new FileOutputStream(file);
			fout.write(bs);
			fout.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		MyCLassLoader loader=new MyCLassLoader();
		Class<?> c=loader.defineClass(bs);
		
		ITest ins=(ITest)c.newInstance();
		ins.setTest(100.0d);
		ins.getMa(-2);
		System.out.println(ins.getTest());
	}
	
	public interface ITest{
		public double getTest();
		public void setTest(double d);
		public void getMa(int a);
	}

	public static class MyCLassLoader extends ClassLoader{
		public Class defineClass(byte[] data){
			return super.defineClass(null,data,0,data.length,null);
		}
	}
}

反编译结果为

import club.jiajia.test3.*;

public class Example implements Cloneable, TestAsm$ITest
{
    private double test = 123.0;
    private int a = 1123;
    
    public double getTest() {
        return this.test;
    }
    
    public void setTest(final double test) {
        this.test = test;
    }
    
    public void getMa(final int i) {
        while (i < 0) {}
        this.a = i;
    }
}

image.png

8.生成更为复杂的方法

package club.jiajia.test3;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

public class TestAsm2 implements Opcodes{
	public static void main(String[] args) throws InstantiationException, IllegalAccessException{
		ClassWriter cw=new ClassWriter(0);
		String className="Example2";
		cw.visit(0x31,ACC_PUBLIC,className,null,"java/lang/Object",new String[]{"java/lang/Cloneable",ITest.class.getName().replace('.','/')});

		String a="a";
		Object av=123;
		
		String getA="getA";
		String setA="setA";
		cw.visitField(ACC_PRIVATE,a,"I",null,av == null?null:Integer.parseInt(av.toString())).visitEnd();

		
		MethodVisitor mv=cw.visitMethod(ACC_PUBLIC,getA,"()I",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		mv.visitFieldInsn(GETFIELD,className,a,"I");
		mv.visitInsn(IRETURN);
		mv.visitMaxs(2,2);
		mv.visitEnd();
		cw.visitEnd();
		
		
		/***********************************************************/
		mv=cw.visitMethod(ACC_PUBLIC,setA,"(II)V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ILOAD, 1);
		mv.visitVarInsn(ILOAD, 2);
		Label label = new Label();
		mv.visitJumpInsn(IF_ICMPLT, label);
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ILOAD, 1);
		mv.visitFieldInsn(PUTFIELD, className, "a", "I");
		
		Label end = new Label();
		mv.visitJumpInsn(GOTO, end);
		mv.visitLabel(label);
		mv.visitFrame(F_SAME, 0, null, 0, null);
		
		mv.visitVarInsn(ALOAD, 0);
		mv.visitVarInsn(ILOAD, 2);
		mv.visitFieldInsn(PUTFIELD, className, "a", "I");
		
		mv.visitLabel(end);
		mv.visitFrame(F_SAME, 0, null, 0, null);
		mv.visitInsn(RETURN);
		mv.visitMaxs(3, 3);
		mv.visitEnd();
		/***********************************************************/
		
		//下面产生构造方法
		mv=cw.visitMethod(ACC_PUBLIC,"<init>","()V",null,null);
		mv.visitCode();
		mv.visitVarInsn(ALOAD,0);
		mv.visitMethodInsn(INVOKESPECIAL,"java/lang/Object","<init>","()V");
		mv.visitInsn(RETURN);
		mv.visitMaxs(1,1);
		mv.visitEnd();
		
		cw.visitEnd();

		byte[] bs=cw.toByteArray();
		File file = new File("E://jiajiajia/Example2.class");
		try {
			FileOutputStream fout = new FileOutputStream(file);
			fout.write(bs);
			fout.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		MyCLassLoader loader=new MyCLassLoader();
		Class<?> c=loader.defineClass(bs);
		
		ITest ins=(ITest)c.newInstance();
		ins.setA(145,12);
		System.out.println(ins.getA());
	}
	
	public interface ITest{
		public int getA();
		public void setA(int a,int b);
	}

	public static class MyCLassLoader extends ClassLoader{
		public Class<?> defineClass(byte[] data){
			return super.defineClass(null,data,0,data.length,null);
		}
	}
}

menu.saveimg.savepath20190322094711.jpg

  • 8
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值