Is Byte Buddy able to Instrumentation#retransformClasses
that are already loaded? I want to use Byte Buddy's Java agent feature so that I don't have to specify the -javaagent
to be able to instrument classes. This is possible for example with Javassist. But I'm evaluating to replace it with Byte Buddy.
I want to insert a static method call before and after certain methods. If that's possible, an short example would be great!
Yes, you can use the AgentBuilder
API for enabling retransformation. Upon installing the agent, Byte Buddy will retransform all classes that are already loaded. You can enable retransformation like this:
AgentBuilder builder = new AgentBuilder.Default()
.with(RedefinitionStrategy.RETRANSFORMATION)
.with(InitializationStrategy.NoOp.INSTANCE)
.with(TypeStrategy.Default.REDEFINE);
You might wonder about the different switches you need to turn:
You need to enabled redefinition (either redefinition or retransformation according to the instrumentation API).
You need to disable an explicit initialization strategy. Otherwise, Byte Buddy attempts to add an explicit initializer into any generated class in order to inject any values into the class once it is loaded. This would change the class layout what the current implementation of the HotSpot VM does not support.
One limitation of the instrumentation API is - as mentioned - that you cannot add any new methods. By default, Byte Buddy copies the code of any intercepted method into a new method what violates this priniciple. By enabling de redefinition type strategie, you make sure Byte Buddy never rebases a method.
Alternatively, you can choose to not use Byte Buddy's interception API which now fully replaces methods that are intercepted but to do manual redefinition using for example the recently added Advice
class.
This way, you can enhance existing code by advicing to your own code such as Advice.to(Foo.class)
where the referenced class's byte code is inserted before and after the method being intercepted:
class Foo {
@Advice.OnMethodEnter
@Advice.OnMethodExit
private static void intercept() {
System.out.println("Before/after");
}
}
You can find more information in the javadoc for Advice
.