raphw / byte-buddy

Runtime code generation for the Java virtual machine.
https://bytebuddy.net
Apache License 2.0
6.27k stars 804 forks source link

Migrating from ASM to ByteBuddy #1466

Closed rupinder10 closed 1 month ago

rupinder10 commented 1 year ago

I have migrated from ASM to ByteBuddy and have been able to replace by ClassFileTransformer to use Advice instead. In my old code, I used to be able to add and remove instrumentation using a switch. It was roughly like this:

ClassFileTransformer transformer = ...
if (config.enable) {
  instrumentation.addTransformer(tranformer, true);
} else {
  instrumentation.removeTransformer(tranformer);
}
instrumentation.retransformClasses(classes);

The corresponding code with ByteBuddy that works:

AgentBuilder agentBuilder = new AgentBuilder.Default().disableClassFormatChanges()
                .with(RedefinitionStrategy.RETRANSFORMATION);

agentBuilder = agentBuilder.type(ElementMatchers.named(className))
        .transform((builder, typeDescription, classLoader, module, protectionDomain) -> builder
        .visit(getAdvice(MyAdvice.class).on(ElementMatchers.nameEndsWith(methodName))));

agentBuilder.installOn(instrumentation);

But there are two aspects I need help with:

  1. How do remove the instrumentation and switch back to the original class ?
  2. I also need to sometimes need the original byte[] of the uninstrumented class. How do I that ?
dogourd commented 1 year ago

After calling installOn, you will get a ResettableClassFileTransformer, you can remove the ClassFileTransformer and retransform the classes by calling the reset method.

You can use AgentBuilder#with(TransformerDecorator) to specify a decorator where you can get the byte array of the class passed to ClassFileTransformer. You can also use net.bytebuddy.dynamic.DynamicType.Builder.make().getBytes() in the implementation of net.bytebuddy.agent.builder.AgentBuilder.Transformer#transform to get it, depending on your needs

rupinder10 commented 1 year ago

I will try those. Just to clarify for the reset you means something like this ?

When I want to instrument :

ResettableClassFileTransformer resettableClassFileTransformer = agentBuilder.installOn(instrumentation);

and then we I want to remove the instrumentation :

instrumentation.removeTransformer(resettableClassFileTransformer);
resettableClassFileTransformer.reset(instrumentation, RedefinitionStrategy.RETRANSFORMATION);
rupinder10 commented 1 year ago

Another question. Is there a way for me to check the results of a transformation to determine whether the class was changed at all ? Using your suggestions I can get the bytes before and after to compare. but is there a simpler approach ?

raphw commented 1 year ago

The first line will break the second. With reset, you undo the instrumentation by transforming back the classes. By removing the transformer, you will simply no longer transform classes later.

rupinder10 commented 1 year ago

Thanks