I have a problem I am not able to solve. Let's assume we have the following two classes and an inheritance relationship:
public class A {
}
public class B extends A {
public void foo() {}
}
I want to instrument additional code such that it looks as follows:
public class A {
public void print() { }
}
public class B extends A {
public void foo() { print(); }
}
In order to achieve this goal, I based my implementation on the java.lang.instrument
package, using an Agent with my own class file transformer. The mechanism is also referred to as dynamic bytecode instrumentation.
Piece of cake so far. Now, my test method does the following:
Code:
B b = new B();
b.foo();
This does not work due to the following restriction in the instrumentation package: when calling new B()
, the instrumentation starts with class B and ends up in a compilation error when loading the manipulated class as the super class A has no print() method yet! The question arises if and how I can trigger the instrumentation of class A before class B. The transform() method of my classfiletransformer should be invoked with class A explicitly! So I started reading and bumped into this:
The java.lang.instrument.ClassFileTransformer.transform()
's javadoc says:
The transformer will be called for every new class definition and every class redefinition. The request for a new class definition is made with ClassLoader.defineClass. The request for a class redefinition is made with Instrumentation.redefineClasses or its native equivalents.
The transform method comes along with a class loader instance, so I thought, why not calling the loadClass
method (loadClass
calls defineClass
) myself with class A when the instrumentation of B has started.
I expected that the instrument method will be called as a result but sadly this was not the case. Instead the class A
was loaded without instrumentation. (The agent does not intercept the load process although it is supposed to)
Any ideas, how to solve this problem? Do you see a reason why it is not possible that an agent that manipulates some bytecode cannot manually load another class that is then hopefully also send through that/any agent?
Note that the following code works properly since A was loaded and instrumented before B is manipulated.
A a = new A();
B b = new B();
b.foo();
Thanks a lot!