Java ASM在运行时覆盖现有的类/方法

时间:2014-07-10 06:06:55

标签: java java-bytecode-asm

我的目标是转换此类

public Class C {
    public static void print(int i) {
        System.out.println(i);
    }
}

进入此类,然后使用此序列调用print()方法

C.print(1);  // call original method

// Code that overrides existing class  

C.print(2);  // call overridden method

如,

    public Class C {
        public static void print(int i) {
            System.out.println(i);
            System.out.println(i);
        }
    }

我一直在阅读http://download.forge.objectweb.org/asm/asm4-guide.pdf的文档,但我似乎无法想象如何覆盖现有的类/方法。 (我想在内存中做所有事情,我不想把类写入磁盘。)我已经能够用类加载器动态创建类,并用反射调用更改的方法,但我不明白如何覆盖现有的。

到目前为止,这是我的尝试。

import org.objectweb.asm.*;

public class MainClass implements Opcodes {

    public static void main(String[] args){
        try {
            // print out original method
            C.print(1);
            // new line to separate calls
            System.out.println();

            // get the bytes i want to inject
            byte[] b1 = CDump.dump();

            // dynamically load the class
            MyClassLoader loader = new MyClassLoader();
            Class<?> myClass = loader.defineClass("C", b1);
            // invoke the method
            myClass.getMethods()[0].invoke(null, new Object[] { 2 });
            // new line to separate calls
            System.out.println();

            // ??? (code that overrides existing class)

            // i want to call the overridden method
            C.print(2);

        } catch (Exception e) {
        e.printStackTrace();
        }
}

public class MyClassLoader extends ClassLoader {

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

}

来自ASMifier的代码。这包含我想要进行的编辑

public class CDump implements Opcodes {

    public static byte[] dump() throws Exception {

        ClassWriter cw = new ClassWriter(0);
        MethodVisitor mv;

        cw.visit(V1_7, ACC_PUBLIC + ACC_SUPER, "C", null, "java/lang/Object", null);

        cw.visitSource("C.java", null);

        {
            mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(2, l0);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V");
            mv.visitInsn(RETURN);
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLocalVariable("this", "LC;", null, l0, l1, 0);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }
        {
            mv = cw.visitMethod(ACC_PUBLIC + ACC_STATIC, "print", "(I)V", null, null);
            mv.visitCode();
            Label l0 = new Label();
            mv.visitLabel(l0);
            mv.visitLineNumber(19, l0);
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitVarInsn(ILOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V");
            Label l1 = new Label();
            mv.visitLabel(l1);
            mv.visitLineNumber(20, l1);
            mv.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
            mv.visitVarInsn(ILOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V");
            Label l2 = new Label();
            mv.visitLabel(l2);
            mv.visitLineNumber(21, l2);
            mv.visitInsn(RETURN);
            Label l3 = new Label();
            mv.visitLabel(l3);
            mv.visitLocalVariable("i", "I", null, l0, l3, 0);
            mv.visitMaxs(2, 1);
            mv.visitEnd();
        }
        cw.visitEnd();

        return cw.toByteArray();
    }
}

感谢任何帮助

0 个答案:

没有答案