javassist.CannotCompileException: [source error] 没有这样的 class: TestDebug

javassist.CannotCompileException: [source error] no such class: TestDebug

我正在尝试使用字节码工具添加一个 try catch 块

所以基本上,我有一个 class 'Lion'。我想在 try 块中捕获其方法之一 'stayLion()' 的全部内容并给出相应的捕获。

为此,我在转换方法中使用了 method.addCatch()。一切正常,除了当我尝试在 catch 块 'TestDebug test = new TestDebug()' 中添加此语句时。 我无法创建自己定义的对象 class。

另外,有没有其他更简单的过程可以使用BCI在try catch块中捕获方法体?

package com.javapapers.java.instrumentation;

public class TestInstrumentation {
    public static void main(String args[]) throws InterruptedException {
        Lion l = new Lion();
        l.runLion();
        l.stayLion();
        System.out.println("The program has ended!");
    }
}

package com.javapapers.java.instrumentation;

import java.io.Serializable;

//to be instrumented java class
public class Lion implements Serializable{
    public static int counter =0;
    public String testing = "This is just to create an object. This is a final testing!!!";
    public void runLion() throws InterruptedException {
        counter++;
        System.out.println("Lion is going to run........!!!");
        Thread.sleep(2000L);
    }


    public void stayLion() throws InterruptedException{
        counter++;
        int arr[] = {1,2,3,4};
        System.out.println("The element is " + arr[4]);         //this error is done intentionally to have the catch block implemented
        System.out.println("Lion is going to stay.......!!!");
        Thread.sleep(2000L);
    }

}

package com.javapapers.java.instrumentation;

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

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;

//this class will be registered with instrumentation agent
public class DurationTransformer implements ClassFileTransformer {
    public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined,
            ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
        byte[] byteCode = classfileBuffer;


        if (className.equals("com/javapapers/java/instrumentation/Lion")) {
            System.out.println("Instrumenting......");
            try {
                ClassPool classPool = ClassPool.getDefault();
                CtClass ctClass = classPool.makeClass(new ByteArrayInputStream(classfileBuffer));
                CtMethod[] methods = ctClass.getDeclaredMethods();
                for (CtMethod method : methods) {
                    method.addLocalVariable("startTime", CtClass.longType);
                    method.insertBefore("startTime = System.nanoTime();");
                    method.insertAfter("System.out.println(\"Execution Duration "
                            + "(nano sec): \"+ (System.nanoTime() - startTime) );");
                    method.insertAt(6, "System.out.println(\"This is a success!!!\");");
                    if(method.getName().equals("stayLion"))
                    {   
                        CtClass etype = ClassPool.getDefault().get("java.lang.Exception");
                        method.addCatch("{ System.out.println(\"We have caught the error via Transformer\"); "
                                + "TestDebug test = new TestDebug();"       //The error is here. Not able to create TestDebug object
                                + "test.saveState(this);"
                                + "throw $e; }", etype);
                    }
                }
                byteCode = ctClass.toBytecode();
                ctClass.detach();
                System.out.println("Instrumentation complete.");
            } catch (Throwable ex) {
                System.out.println("Exception: " + ex);
                ex.printStackTrace();
            }
        }
        return byteCode;
    }
}

package com.javapapers.java.instrumentation;

import java.lang.instrument.Instrumentation;

public class DurationAgent {

    // for all the class loaded, premain will be called
    public static void premain(String agentArgs, Instrumentation inst) {
        System.out.println("Executing premain.........");
        inst.addTransformer(new DurationTransformer());
    }
}

package com.javapapers.java.instrumentation;

import java.io.File;
import java.io.IOException;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;


public class TestDebug {

    public TestDebug(){
        System.out.println("We are in constructor");
    }

    public static void saveState(Object emp){

        ObjectMapper mapper = new ObjectMapper();
        //mapper.configure(SerializationConfig.Feature.FAIL_ON_EMPTY_BEANS, false);
        try {
            mapper.writeValue(new File("savedState.json"), emp);
        } catch (JsonGenerationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (JsonMappingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

============================================= ===================================

Exception: javassist.CannotCompileException: [source error] no such class: TestDebug
javassist.CannotCompileException: [source error] no such class: TestDebug
        at javassist.CtBehavior.insertAt(CtBehavior.java:1146)
        at javassist.CtBehavior.insertAt(CtBehavior.java:1073)
        at com.javapapers.java.instrumentation.DurationTransformer.transform(DurationTransformer.java:38)
        at sun.instrument.TransformerManager.transform(Unknown Source)
        at sun.instrument.InstrumentationImpl.transform(Unknown Source)
        at java.lang.ClassLoader.defineClass1(Native Method)
        at java.lang.ClassLoader.defineClass(Unknown Source)
        at java.security.SecureClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.defineClass(Unknown Source)
        at java.net.URLClassLoader.access0(Unknown Source)
        at java.net.URLClassLoader.run(Unknown Source)
        at java.net.URLClassLoader.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at com.javapapers.java.instrumentation.TestInstrumentation.main(TestInstrumentation.java:5)
Caused by: compile error: no such class: TestDebug
        at javassist.compiler.MemberResolver.searchImports(MemberResolver.java:447)
        at javassist.compiler.MemberResolver.lookupClass(MemberResolver.java:412)
        at javassist.compiler.MemberResolver.lookupClassByJvmName(MemberResolver.java:330)
        at javassist.compiler.MemberResolver.resolveJvmClassName(MemberResolver.java:491)
        at javassist.compiler.MemberCodeGen.resolveClassName(MemberCodeGen.java:1146)
        at javassist.compiler.CodeGen.atDeclarator(CodeGen.java:711)
        at javassist.compiler.ast.Declarator.accept(Declarator.java:99)
        at javassist.compiler.CodeGen.atStmnt(CodeGen.java:350)
        at javassist.compiler.ast.Stmnt.accept(Stmnt.java:49)
        at javassist.compiler.Javac.compileStmnt(Javac.java:568)
        at javassist.CtBehavior.insertAt(CtBehavior.java:1125)

为了在 Javaassist 中使用某些 类,您需要指定完整的包名称。

而不是

TestDebug test = new TestDebug();

使用

com.javapapers.java.instrumentation.TestDebug test = new com.javapapers.java.instrumentation.TestDebug();