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

硅谷探秘者 2422 0 0

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

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


猜你喜欢
java基础 1522 asmfor循环语句1.jar包2.原java文件packageclub.jiajia.test3;publicclassExamp4{ publicintmethod(inta
java基础 1843 1.jar包:2.原java文件:packageclub.jiajia.test3;publicclassExamp3{ publicintmethod(inta){ switch(a){ case123: a=1230; break; case128: a=1280; break; case12: a=120; break; } returna
java基础 2146 asm实例对象的调用1.需要的jar包2.我们需要通过asm的目标如下:packageclub.jiajia.test3;publicclassExamp5
其他 8801 在一本书上看到过子可以重载父,关于这一点有点疑惑,个人重载是发在同一个中。网上关于这个也存在争议。先暂时作为一个问题记录在此下面这张图片引用自《疯狂java讲义第三版》关于重写,遵循以
java虚拟机(jvm) 4881 1.内部名在许多情况下,一种型只能是或接口型。例如,一个的超、由一个实现的接口,或者由一个抛出的异常就不能是基元型或数组型,必须是或接口型。这些型在已编译中用内部名字表示
前端(h5) 2218 定义splice()向/从数组中添加/删除项目,然后返回被删除的项目。注意:该会改变原始数组。语arrayObject.splice(index,howmany,item1
前端(h5) 2500 :varmap=newMap();属性:size返回集合中元素的数量:clear从映射中移除所有元素。delete从映射中移除指定的元素。forEach对映射中的每个元素执行指定操作。get
java基础 605 1.关于Calendar的set()延迟修改set(f,value)将日历字段f更改为value,此外它还设置了一个内部员变量,以指示日历字段f已经被更改。尽管日历字段f是立即更改的,但是
归档
2018年11月  12 2018年12月  33 2019年01月  28 2019年02月  28 2019年03月  32 2019年04月  27 2019年05月  33 2019年06月  6 2019年07月  12 2019年08月  12 2019年09月  21 2019年10月  8 2019年11月  15 2019年12月  25 2020年01月  9 2020年02月  5 2020年03月  16 2020年04月  4 2020年06月  1 2020年07月  7 2020年08月  13 2020年09月  9 2020年10月  5 2020年12月  3 2021年01月  1 2021年02月  5 2021年03月  7 2021年04月  4 2021年05月  4 2021年06月  1 2021年07月  7 2021年08月  2 2021年09月  8 2021年10月  9 2021年11月  16 2021年12月  14 2022年01月  7 2022年05月  1 2022年08月  3 2022年09月  2
标签
算法基础 linux 前端 c++ 数据结构 框架 数据库 计算机基础 储备知识 java基础 ASM 其他 深入理解java虚拟机 nginx git 消息中间件 搜索 maven redis docker dubbo vue 导入导出 软件使用 idea插件 协议 无聊的知识 jenkins springboot mqtt协议 keepalived minio mysql ensp 网络基础
目录
余生别太较劲,放过自己 才会幸福。