I have been trying to use a Java agent to apply a bytecode transformation with ASM.
I implemented an Agent with the premain
method adding a transformer to the Instrumentation.
I added the "Premain-Class" line in the .jar manifest
Premain-Class: <MyAgentPath>
Then I tried to run the application with the agent.
There I have a problem : my transformer modifies some method calls, so if not all involved classes are modified too, it cannot work. And there are some classes which are not modified, like "org.apache.commons.math3.util.FastMath". Of course then, I got the error :
java.lang.NoSuchMethodError: org.apache.commons.math3.util.FastMath.floor<new_descriptor>
I checked a lot of posts saying it could be the bootstrap loader which does not know the path to this class so I tried to add it using different ways :
Adding the "Boot-Class-Path" line to the manifest :
Boot-Class-Path: <...>/commons-math3<...>.jar
Using the method "appendToBootstrapClassLoaderSearch(JarFile)"
inst.appendToBootstrapClassLoaderSearch("<...>/commons-math3<...>.jar");
Using the JVM argument "-Xbootclasspath/a:"
-Xbootclasspath/a:<...>/commons-math3<...>.jar
None of this changed anything.
I also used the Instrumentation class method getAllLoadedClasses()
to see which ones were loaded, and all classes involved in the application process where loaded, including FastMath.
for(Class<?> clazz : MyAgent.getInstInstance().getAllLoadedClasses()){
buffWrite.write(clazz.getName());
As the class "FastMath" gave an error and as the Bootstrap Loader should have its path, I tried adding some method calls to methods from other classes in the same package. It appears the problem does not show for every class of the package.
For example: MathUtils
is transformed and a call to the modified method checkFinite(D)V
-> checkFinite<new_descriptor>
.
So I guess the problem has nothing to do with the paths given to the bootstrap loader.
If you have some ideas about what is happening, I would be glad to hear about it!