我的目标是转换此类
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();
}
}
感谢任何帮助