如何使用Javassist创建ArrayList

19

我想在插桩期间将一个arrayList添加到方法中。我按照(Javassist CannotCompileException when trying to add a line to create a Map)中所述的方式尝试实现,但出现了java.lang.VerifyError不同的异常。

    public void createInsertBefore(String scenarioName, String className, CtMethod method,
                                   String insertBefore) throws CannotCompileException {
        method.addLocalVariable("startTime", CtClass.longType);
        StringBuilder bBuilder = new StringBuilder();
        bBuilder.append("startTime = System.nanoTime();");
        bBuilder.append("System.out.println(startTime);");

        if((insertBefore!=null) && !insertBefore.isEmpty()){
            bBuilder.append(insertBefore);
        }

        bBuilder.append("java.util.List metadata = new java.util.ArrayList();");

        System.out.println(bBuilder.toString());
        method.insertBefore(bBuilder.toString());
}

print语句输出的结果是:

startTime = System.nanoTime();
System.out.println(startTime);
java.util.List metadata = new java.util.ArrayList();

但是它会抛出以下异常:

Exception in thread "main" java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at sun.instrument.InstrumentationImpl.loadClassAndStartAgent(InstrumentationImpl.java:382)
    at sun.instrument.InstrumentationImpl.loadClassAndCallPremain(InstrumentationImpl.java:397)
Caused by: java.lang.VerifyError
    at sun.instrument.InstrumentationImpl.retransformClasses0(Native Method)
    at sun.instrument.InstrumentationImpl.retransformClasses(InstrumentationImpl.java:144)
    at org.wso2.das.javaagent.instrumentation.Agent.premain(Agent.java:57)
    ... 6 more
FATAL ERROR in native method: processing of -javaagent failed
Aborted (core dumped)

情况和之前一样,但为什么会抛出不同的异常。我做错了什么...求帮助...

更新1

添加了一些行(我已删除一些打印行),insertBefore,

 startTime = System.nanoTime();
 java.util.List metadata = new java.util.ArrayList();

insertAt

System.out.println("prepareStatement is running");
java.util.Map/*<String,String>*/ arbitraryMap = new java.util.HashMap/*String,String>*/();
arbitraryMap.put("query",$1);System.out.println(arbitraryMap);

insertAfter

System.out.println(System.nanoTime()-startTime);

看起来是本地代码错误。 - Thomas
你的代码可能是错误的,但错误发生在这里:sun.instrument.InstrumentationImpl.retransformClasses0(Native Method),也就是说出了问题的是本地代码。你所得到的错误的 JavaDoc 说:当“验证程序”检测到一个类文件虽然格式正确,但包含某种内部不一致或安全问题时抛出异常。 - 这可能取决于正在增强的类,也许你正在尝试两次插入或者已经有一个名为 startTimemetadata 等的变量。 - Thomas
这让我感到非常困惑,当我删除创建List的那一行时,它可以正常工作。但是,当我保留该行并删除insertAfter中的(startTime行,如上面的更新所示)时,它也可以正常工作。但是当我两者都保留时,它会抛出异常。 - udani
顺便问一下,为什么你要为 startTime 创建一个本地变量,但是将 metadata 添加为字符串命令?我对 Javassist 不是很了解,所以这可能是唯一的方法 - 这只是一个猜测,因为如果其中一个有效而另一个无效,则必定存在引入不兼容性的差异。 - Thomas
1
insertBefore 变量包含什么内容? - Ricard Nàcher Roig
显示剩余3条评论
1个回答

7
VerifyError是指虚拟机发现已编译的字节码无效时出现的错误。例如,当您尝试使用整数的加载指令读取长变量时或类似情况。

因此,在您的情况下,代码编译,javaassist进行其操作,但虚拟机不接受该代码。这必须是javassist中的错误或其用法中的错误。

如何解决:

1)据我所知,您只能使用insertBefore在方法开头添加一个语句(而不是一行)。如果您想添加多个,请将它们包装在大括号{}中,例如method.insertBefore("{" + bBuilder.toString() + "}")。

2)您未将元数据作为变量添加,就像使用startTime一样。

X)如果仍然存在此或其他错误,请尝试将类文件写入磁盘上的文件(使用toClassFile,您可以将修改后的类文件作为byte[]访问)。然后,您可以使用javap等工具查看已编译的代码,并更清楚地了解正在发生的情况。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接