I’m using a Java Agent (Agent.class) to transform a method in a program (Program.class) in a way that includes a call to the Agent class.
public Program.getMultiplier()F: ALOAD 1 ALOAD 2 FDIV + INVOKESTATIC Agent.getCustomMultiplier(F)F FRETURN
I’ve inspected the class loaders and their parents of both Agent and Program classes, and their hierarchy looks like this:
- Agent.class:
AppClassLoader
<-PlatformClassLoader
<-null
- Program.class:
URLClassLoader
<-PlatformClassLoader
<-null
When the Program executes the added INVOKESTATIC
instruction, it throws a ClassNotFoundException — it cannot find the Agent class as it was loaded by a different class loader.
As a temporary solution, I’ve tried forcing AppClassLoader
to become a parent of URLClassLoader
with reflection, which works in older Java versions but has been removed since Java 12.
Is there a more reliable way to make sure my Agent class is visible from any class loader?
Advertisement
Answer
You can add classes to the bootstrap class loader using appendToBootstrapClassLoaderSearch
. This makes the classes of the specified jar file available to all classes whose defining class loader follows the standard delegation pattern.
But this requires the classes to be packaged in a jar file. When you specify the Agent’s own jar file, you have to be aware that classes loaded through the bootstrap loader are distinct from the classes loaded through the app loader, even when they originate from the same jar file. Further, the classes loaded by the bootstrap loader must not have dependencies to classes loaded by by other class loaders.
If your getCustomMultiplier
method is supposed to interact with the running Agent, you have to separate the agent and the class containing this method.