I wrote a javaagent by myself to dynamically instrumenting the java classes with ASM (I am not using the COMPUTE_MAXS
or COMPUTE_FRAMES
of ASM, I do that manually by myself). Actually, I am just trying to use a big try-catch block for non-constructor methods to capture the uncaught Exceptions or Errors and record such events (my code is actually the revised version of the code in this question).
However, when I tried to use my javaagent in the testing process of an open-source project joda-time, the following error occured:
org.apache.maven.surefire.testset.TestSetFailedException: org.joda.time.TestAllPackages
at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:116)
at org.apache.maven.surefire.junit.JUnit3Provider.executeTestSet(JUnit3Provider.java:140)
at org.apache.maven.surefire.junit.JUnit3Provider.invoke(JUnit3Provider.java:113)
at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:379)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:340)
at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:125)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:413)
Caused by: java.lang.LinkageError: loader (instance of sun/misc/Launcher$AppClassLoader): attempted duplicate class definition for name: "org/joda/time/DateTimeZone"
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at org.joda.time.TestChronology.<clinit>(TestChronology.java:47)
at org.joda.time.TestAll.suite(TestAll.java:37)
at org.joda.time.TestAllPackages.suite(TestAllPackages.java:36)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.common.junit3.JUnit3Reflector.createInstanceFromSuiteMethod(JUnit3Reflector.java:157)
at org.apache.maven.surefire.common.junit3.JUnit3Reflector.constructTestObject(JUnit3Reflector.java:124)
at org.apache.maven.surefire.junit.JUnitTestSet.execute(JUnitTestSet.java:75)
... 6 more
To my understanding, each time when sun/misc/Launcher$AppClassLoader
is trying to load a class, the transform
method of ClassFileTransformer
is entered. The class is finally loaded after I modified the class and return the modified byte array. Therefore, every class should be loaded only once.
I further tried to print out the class name and the loader which loads it in the begining of the transform
method, I found that org/joda/time/DateTimeZone
appears only once, which is consistent with my understanding.
So now the only thing inconsistent with my understanding is the error. Why sun/misc/Launcher$AppClassLoader attempted duplicate class definition
with my agent? Every went so soomthly when I removed my -javaagent
option.