Javassist:javassist.CannotCompileException:by java.lang.ClassFormatError:类文件

时间:2015-11-25 10:20:36

标签: java eclipse runtime-error javassist

我正在使用javassist来更改方法体。在应用程序中定义方法时,我可以这样做。但是,当我想更改应用程序使用的jar文件中定义的方法时,我得到以下运行时错误:

javassist.CannotCompileException: by java.lang.ClassFormatError: Duplicate method name&signature in class file pk1/StringBuilder.

以下代码用于更改方法正文。我正在使用eclipse IDE。调用 clas.toClass(); 时会发生错误。

public class JassistTiming {

public static void main(String[] arg) {

    //first parameter is name of class, and the second one is name of method
    String[] argv = {"pk1.StringBuilder","buildString"};

    // start by getting the class file and method
    CtClass clas = ClassPool.getDefault().get(argv[0]);

    // add timing interceptor to the class
    addTiming(clas, argv[1]);
    clas.writeFile();
    System.out.println("Added timing to method " + argv[0] + "." + argv[1]);

    clas.toClass(); //Run time error happens here                                             
}

private static void addTiming(CtClass clas, String mname) throws NotFoundException, CannotCompileException {

    CtMethod mold = clas.getDeclaredMethod(mname);

    String nname = mname+"$impl";
    mold.setName(nname);
    CtMethod mnew = CtNewMethod.copy(mold, mname, clas, null);

    String type = mold.getReturnType().getName();
    StringBuffer body = new StringBuffer();
    body.append("{\nlong start = System.currentTimeMillis();\n");
    if (!"void".equals(type)) {
        body.append(type + " result = ");
    }
    body.append(nname + "($$);\n");

    body.append("System.out.println(\"Call to method " + mname +
        " took \" +\n (System.currentTimeMillis()-start) + " +
        "\" ms.\");\n");
    if (!"void".equals(type)) {
        body.append("return result;\n");
    }
    body.append("}");

    mnew.setBody(body.toString());
    clas.addMethod(mnew);
}
}

更新:StringBuilder的代码:

public class StringBuilder { 

public String buildString(int length) { 

    String result = ""; 

    for (int i = 0; i < length; i++) { 
        result += (char)(i%26 + 'a'); 
    } 

    return result; 
} 

2 个答案:

答案 0 :(得分:0)

我发现了问题。在第一次运行中,程序运行正常,并创建了 StringBuilder 的新类文件。但是,在下一次运行中,Eclipse不会覆盖此类,并且我得到上述运行时错误。如果我手动删除这个类文件,那么该程序适用于下一次运行。

我从应用程序创建一个jar文件并在命令行中运行它,它工作正常。因此,问题在于Eclipse无法覆盖创建的类文件。

答案 1 :(得分:0)

我相信我找到了原因。

假设foobar.jar包含班级pk1.StringBuilder

以下工作

java -cp javassist-3.7.ga.jar:foobar.jar:. JassistTiming 
java -cp javassist-3.7.ga.jar:foobar.jar:. JassistTiming 

检测类StringBuilder.class存储在子目录pk1中,并调用检测方法。

以下工作也是如此

java -cp javassist-3.7.ga.jar:.:foobar.jar JassistTiming 

但第二次执行失败,因为类StringBuilder.class现在首先在子目录pk1中找到,这是已经检测过的类,因此方法public void buildString$impl()已经存在于此类中