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

时间:2017-02-09 11:23:10

标签: java bytecode instrumentation javassist

我正在尝试使用字节码检测添加try catch块

基本上,我有一个班级'狮子'。我想捕捉其中一种方法的全部内容' stayLion()'在try块中并给出相应的catch。

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

此外,还有其他更简单的过程来使用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.access$100(Unknown Source)
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.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)

1 个答案:

答案 0 :(得分:1)

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

而不是

TestDebug test = new TestDebug();

使用

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