java - 在java中使用ASM4.0跟踪方法——转换后的方法被破坏(NoSuchMethodError)

标签 java trace java-bytecode-asm nosuchmethoderror

我正在尝试 ASM 4.0我在管理我的经纪人时遇到了一些麻烦。我有一个类 TraceTransformer 应该转换字节码,但是出了问题——当我尝试转换它时,似乎我访问的每个类都被毁了。

代理

JavaTraceAgent.java:

package traceagent;

import java.lang.instrument.Instrumentation;


public class JavaTraceAgent {
    private static Instrumentation instrumentation;
    private static String agentId = "Uninitialized";

    public static void premain(String args, Instrumentation inst) throws Exception {
        instrumentation = inst;
        instrumentation.addTransformer(new TraceTransformer());
    }

    public static void agentmain(String args, Instrumentation inst) throws Exception {
        instrumentation = inst;
        instrumentation.addTransformer(new TraceTransformer());
    }

    public static void initialize() {
        if (instrumentation == null) {
            JavaAgentLoader.loadAgent();
        }
    }

    public static void logMethodInvocation() {
        System.out.println("Logging invocation...");
        //Thread.dumpStack();
        System.out.println("logging complete!");
    }

    public static void setAgentId(String _agentId) {
        agentId = _agentId;
    }
}

TraceTransformer.java

package traceagent;

import java.lang.instrument.ClassFileTransformer;
import java.lang.instrument.IllegalClassFormatException;
import java.security.ProtectionDomain;

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;

public class TraceTransformer implements ClassFileTransformer {

    @Override
    public byte[] transform(ClassLoader loader, String className,
            Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
            byte[] classfileBuffer) throws IllegalClassFormatException {

        if (!className.contains("superman")) return classfileBuffer;

        System.out.println("TraceTransformer invoked on " + className);

        ClassReader reader = new ClassReader(classfileBuffer);
        ClassWriter writer = new ClassWriter(reader, 0);

        ClassVisitor visitor = new ClassVisitor(Opcodes.ASM4, writer) {

            @Override
            public MethodVisitor visitMethod(int access, final String name, String desc, String signature, String[] exceptions) {
            return new MethodVisitor(Opcodes.ASM4) {
                @Override
                public void visitCode() {
                    if (name.contains("sayHello")) {
                            super.visitMethodInsn(Opcodes.INVOKESTATIC, "traceagent/JavaTraceAgent", "logMethodInvocation", "()V");
                            System.out.println("Injecting logger on " + name);
                    } 
                    super.visitCode();
                }
            };
        }
    };

    reader.accept(visitor, 0);

    return writer.toByteArray();    
}

}

list

build.xml:

    ...
    <manifest>
        <attribute name="Built-By" value="${user.name}"/>
        <attribute name="Class-Path" value="${manifest.classpath}"/>
        <attribute name="Agent-Class" value="traceagent.JavaTraceAgent" />
        <attribute name="Can-Redefine-Classes" value="true" />
        <attribute name="Can-Retransform-Classes" value="true" />
        <attribute name="Premain-Class" value="traceagent.JavaTraceAgent" />
    </manifest>
    ...

Target

Program.java (entry point):

package jack;

import jack.superman.Hello;

public class Program {
    /**
    * @param args
    */
    public static void main(String[] args) {
        Hello.sayHello();
    }

}

Hello.java:

package jack.superman;

public class Hello {

    public static void sayHello() {
        System.out.println("Hello");
    }
}

当前程序

...\src> javac -d . jack\Program.java
...\src> java --javagent:jack\TAgent.jar jack.Program
TraceTransformer invoked on jack/superman/Hello
Injecting logger on sayHello
Exception in thread "main" java.lang.NoSuchMethodError: jack.superman.Hello.sayHello()V
        at jack.Program.main(Program.java:10)

我在这里做错了什么?如何避免“破坏”该方法?

最佳答案

我测试了你的代码,得到了同样的错误,但经过一些测试和阅读文档后,我让它工作了。问题出在您的 ClassVisitorMethodVisitor 中。这是代码。

ClassVisitor visitor = new ClassVisitor(Opcodes.ASM4, writer) {
    @Override
    public MethodVisitor visitMethod(int access, final String name, String desc, String signature, String[] exceptions) {
        MethodVisitor mv = cv.visitMethod(access, name, desc, signature, exceptions);
        if (!name.contains("sayHello")) return mv;
            
        MethodVisitor mv2 = new MethodVisitor(Opcodes.ASM4, mv) {
            public void visitCode() {
                mv.visitMethodInsn(Opcodes.INVOKESTATIC, "traceagent/JavaTraceAgent", "logMethodInvocation", "()V");
            }
        };
            
        return mv2;
    }
};

输出为

TraceTransformer invoked on jack/superman/Hello

Loggin invocation...

loggin complete!

Hello

关于java - 在java中使用ASM4.0跟踪方法——转换后的方法被破坏(NoSuchMethodError),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19010767/

相关文章:

java - ASM 字节码 View 显示 "//couldn' t generate bytecode view, no .class file found”

java - 合并 int[] 和 String[] 应该产生 Object[]

java - 对 lambdaj 的实用介绍?

使用 ArrayLists 时出现 java 错误 - 无法编译

c - 如何编译和运行FNV Hash

spring-boot - 如何记录/跟踪来自 java spring 应用程序的 redis 调用

java - ASM 中的类编写器 COMPUTE_FRAMES

java - C# 实现 - "Print all combinations of balanced parentheses"

java - 来自 xsd 的动态 java bean

c# - 跟踪无效的回发或回调参数