java asm GeneratorAdapter生成子类并加载

1 篇文章 0 订阅
1 篇文章 0 订阅

加载器:

package com.zz4955.asm.generatoradaptor;

public class MyClassLoader extends ClassLoader {

    public Class defineClass(String name, byte[] b) {
        return defineClass(name, b, 0, b.length);
    }
}

接口:

package com.zz4955.asm.generatoradaptor;

public interface Graph {
    String getShape();
}

子类,java代码如下,后面会用GeneratorAdapter生成这个子类的字节码:

package com.zz4955.asm.generatoradaptor;

public class Circle implements Graph {

    private String shape;

    public Circle(String shape) {
        this.shape = shape;
    }

    @Override
    public String getShape() {
        return shape;
    }
}

GeneratorAdapter来生成上面的子类:

package com.zz4955.asm.generatoradaptor;

import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Type;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.objectweb.asm.commons.Method;

import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.RETURN;

public class GenerateAsmCode {

    public byte[] getCodeByGeneratorAdaptor(String className, String functionName, Class interf) { // 创建一个Graph接口的实现类,这个类与com.zz4955.asm.generatoradaptor.Circle类似。
        String clsLastName = "<init>";
        String varName = "shape";
        ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_FRAMES); // 注意:这个ClassWriter.COMPUTE_FRAMES,不能为0!

        // 生成类信息
        cw.visit(V1_6, ACC_PUBLIC + ACC_SUPER, className.replace('.', '/'), null, "java/lang/Object", new String[] {Type.getType(interf).getInternalName()});
        cw.visitField(ACC_PRIVATE, varName, Type.getDescriptor(String.class), null, null).visitEnd();

        // 生成带有一个参数的构造函数
        Method initMethod = new Method(clsLastName, Type.VOID_TYPE, new Type[]{Type.getType(String.class)}); // 带有一个参数的构造函数
        GeneratorAdapter initAdapter = new GeneratorAdapter(ACC_PUBLIC, initMethod, null, null, cw);
        initAdapter.visitCode();
        initAdapter.loadThis();
        initAdapter.invokeConstructor(Type.getType(Object.class), Method.getMethod("void <init> ()"));
        initAdapter.loadThis();
        initAdapter.loadArg(0);
        initAdapter.putField(Type.getObjectType(className.replace('.', '/')), varName, Type.getType(String.class));
        initAdapter.returnValue();
        initAdapter.endMethod();
        initAdapter.visitEnd();

        // 生成接口方法
        Method funMethod = new Method(functionName, Type.getType(String.class), new Type[]{});
        GeneratorAdapter funAdaper = new GeneratorAdapter(ACC_PUBLIC, funMethod, null, null, cw);
        funAdaper.visitCode();
        funAdaper.loadThis();
        funAdaper.getField(Type.getObjectType(className.replace('.', '/')), varName, Type.getType(String.class));
        funAdaper.returnValue();
        funAdaper.endMethod();
        funAdaper.visitEnd();
        cw.visitEnd();

        return cw.toByteArray();
    }
}

客户端:

package com.zz4955.asm.generatoradaptor;

import java.io.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;

public class GeneratorAdatperClient {

    public static void main(String[] args) throws Exception {
        MyClassLoader myClassLoader = new MyClassLoader();

        // 加载接口
        String graphfilepath = "F:\\asm_ex\\target\\classes\\com\\zz4955\\asm\\generatoradaptor\\Graph.class";
        byte[] codeGraph = inputStream2ByteArray(graphfilepath);
        Class clsGraph = myClassLoader.defineClass("com.zz4955.asm.generatoradaptor.Graph", codeGraph);
        System.out.println(clsGraph.getCanonicalName());

        // 生成目标类并
        GenerateAsmCode generateAsmCode = new GenerateAsmCode();
        String className2 = "com.zz4955.asm.generatoradaptor.Circle";
        String functionName2 = "getShape";
        byte[] code = generateAsmCode.getCodeByGeneratorAdaptor(className2, functionName2, clsGraph);

        writeToFile(code);

        Class cls = myClassLoader.defineClass(className2, code);
        Constructor constructor = cls.getDeclaredConstructor(new Class[]{String.class});
        constructor.setAccessible(true);
        Object obj = constructor.newInstance(new Object[]{"shape is circle"});
        Method method = cls.getMethod(functionName2);
        System.out.println(method.invoke(obj));
    }

    private static void writeToFile(byte[] code) throws Exception {
        OutputStream out = new FileOutputStream("f:/Circle.class");
        InputStream is = new ByteArrayInputStream(code);
        byte[] buff = new byte[1024];
        int len = 0;
        while((len=is.read(buff))!=-1){
            out.write(buff, 0, len);
        }
        is.close();
        out.close();
    }

    private static byte[] inputStream2ByteArray(String filePath) throws IOException {
        InputStream in = new FileInputStream(filePath);
        byte[] data = toByteArray(in);
        in.close();

        return data;
    }

    private static byte[] toByteArray(InputStream in) throws IOException {
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024 * 4];
        int n = 0;
        while ((n = in.read(buffer)) != -1) {
            out.write(buffer, 0, n);
        }
        return out.toByteArray();
    }
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值