我是ASM框架的新手。我一直在围绕这个ASM框架工作一周。我在网上看到了有关解析类和从头开始生成.class文件的教程。但是无法遵循如何在ASM中修改现有的类。
我无法跟踪ClassVisitor
,ClassWriter
和ClassReader
之间的执行流程。
请为我提供以下代码的ASM示例,请解决我的问题。
public class ClassName {
public void showOne() {
System.out.println("Show One Method");
}
public static void main(String[] args) {
ClassName c = new ClassName();
c.showOne();
}
}
以上类应修改为:
public class ClassName {
public void showOne() {
System.out.println("Show One Method");
}
public void showTwo() {
System.out.println("Show Two Method");
}
public static void main(String[] args) {
ClassName c = new ClassName();
c.showOne();
c.showTwo();
}
}
应该用什么ASM代码进行修改?
我使用ASMifier工具生成代码。但我不知道在哪里应用。
您的要求有些不足。下面是一个示例程序,该程序使用ASM的visitor API将假定具有问题结构的类转换为结果类。我添加了一个方便的方法,该方法采用一个字节数组并返回一个字节数组。在两种情况下都可以使用这种方法,将静态转换应用于磁盘上以及Instrumentation代理中的类文件。
当将ClassWriter
与传递给ClassVisitor
的ClassReader
组合如下时,它将自动复制源类的每个功能,因此您仅需覆盖要应用更改的这些方法。
这里,遇到visitMethod
方法对其进行修改时,main
被覆盖以进行拦截,而visitEnd
被覆盖以附加全新的showTwo
方法。 MainTransformer
会拦截RETURN
指令(在您的示例中应该只有一个),以在其之前插入对showTwo
的调用。
import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter;
public class MyTransformer extends ClassVisitor {
public static byte[] transform(byte[] b) {
final ClassReader classReader = new ClassReader(b);
final ClassWriter cw = new ClassWriter(classReader,
ClassWriter.COMPUTE_FRAMES|ClassWriter.COMPUTE_MAXS);
classReader.accept(new MyTransformer(cw), ClassReader.EXPAND_FRAMES);
return cw.toByteArray();
}
public MyTransformer(ClassVisitor cv) {
super(Opcodes.ASM5, cv);
}
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
MethodVisitor v=super.visitMethod(access, name, desc, signature, exceptions);
if(name.equals("main") && desc.equals("([Ljava/lang/String;)V"))
v=new MainTransformer(v, access, name, desc, signature, exceptions);
return v;
}
@Override
public void visitEnd() {
appendShowTwo();
super.visitEnd();
}
private void appendShowTwo() {
final MethodVisitor defVisitor = super.visitMethod(
Opcodes.ACC_PUBLIC, "showTwo", "()V", null, null);
defVisitor.visitCode();
defVisitor.visitFieldInsn(Opcodes.GETSTATIC,
"java/lang/System", "out", "Ljava/io/PrintStream;");
defVisitor.visitLdcInsn("Show Two Method");
defVisitor.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"java/io/PrintStream", "println", "(Ljava/lang/String;)V", false);
defVisitor.visitInsn(Opcodes.RETURN);
defVisitor.visitMaxs(0, 0);
defVisitor.visitEnd();
}
class MainTransformer extends GeneratorAdapter
{
MainTransformer(MethodVisitor delegate, int access, String name, String desc,
String signature, String[] exceptions) {
super(Opcodes.ASM5, delegate, access, name, desc);
}
@Override
public void visitInsn(int opcode) {
if(opcode==Opcodes.RETURN) {
// before return insert c.showTwo();
super.visitVarInsn(Opcodes.ALOAD, 1); // variable c
super.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
"ClassName", "showTwo", "()V", false);
}
super.visitInsn(opcode);
}
}
}