我希望在下面的代码中调用newTarget.a()和newTarget.b()时应用调制后的ASM类,以便它看起来像这样
当调用应用了修改的ASM类的newTarget.a()和newTarget.b()时,如何获得以下结果?
码:
package asm;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
import static org.objectweb.asm.Opcodes.ASM5;
public class Main {
public static void main(String[] args) throws Exception {
Target target = new Target();
target.a();
target.b();
ClassReader reader = new ClassReader("asm.Main$Target");
ClassWriter writer = new ClassWriter(0);
ClassVisitor visitor = new TestClassVisitor(ASM5, writer);
reader.accept(visitor, 0);
byte[] transformed = writer.toByteArray();
// Apply byte[] transformed
Target newTarget = new Target();
newTarget.a();
newTarget.b();
}
static class Target {
private void a() {
System.out.println("first method");
}
private void b() {
System.out.println("second method");
}
}
static class TestClassVisitor extends ClassVisitor {
public TestClassVisitor(int i, ClassVisitor classVisitor) {
super(i, classVisitor);
}
@Override
public MethodVisitor visitMethod(int i, String s, String s1, String s2, String[] strings) {
MethodVisitor visitor = super.visitMethod(i, s, s1, s2, strings);
if (!s.equals("<init>")) {
return visitor;
}
return new TestMethodVisitor(api, visitor);
}
}
static class TestMethodVisitor extends MethodVisitor {
public TestMethodVisitor(int i, MethodVisitor methodVisitor) {
super(i, methodVisitor);
}
@Override
public void visitCode() {
super.visitCode();
super.visitFieldInsn(Opcodes.GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
super.visitLdcInsn("transformed method");
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
}
@Override
public void visitEnd() {
super.visitEnd();
}
}
}
想要结果:
第一种方法
第二种方法
转换方法
第一种方法
转换方法
第二种方法
最佳答案
您正在寻找Java Instrumentation
API。它要求您通过-javaagent
参数附加Java代理。使用API,您可以调用:
instrumentation.redefineClasses(
new ClassDefinition(asm.Main.Target.class, classWriter.toBytes())
);
确保不更改类的布局,大多数JVM当前不支持此布局。