I want to add a arrayList into a method during instrumentation. I tried it as mentioned in (Javassist CannotCompileException when trying to add a line to create a Map) but it throws a different exception with a 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());
}
Output received from the print statement is,
startTime = System.nanoTime();
System.out.println(startTime);
java.util.List metadata = new java.util.ArrayList();
But it throws following exception,
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)
The situation is same as earlier, but why does it throw a different exception. What am i doing wrong....some help please...
Update 1
lines added with (I have removed some print lines), 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);
A VerifyError
occurs when the VM notices, that an already compiled bytecode is not valid. For example, when you try to read a long variable using a load instruction for an integer, or similar things.
So, in your case, the code compiles, javaassist does its magic, but the VM does not accept the code. It must be either a bug in javassist or a bug in its usage.
How to fix it:
1) As far as I know, you can only add one statement (not one line) at the beginning of a method using insertBefore
. If you want to add more than one, wrap them in braces {}
, something like method.insertBefore("{" + bBuilder.toString() + "}"
);
2) You did not add the metadata as a variable like you did with startTime
X) If this or another error still persists, try to write the class file to a file on disk (using toClassFile
you can access the modified class file as a byte[]
). Then you can use tools like javap to look at the compiled code, and see more clearly what is going on.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With