byte-buddy icon indicating copy to clipboard operation
byte-buddy copied to clipboard

Transformation Listener not being invoked

Open rupinder10 opened this issue 2 years ago • 10 comments

I have a listener registered as under but it never get invoked. The classes are being transformed fine but the listener methods are not working. What am I missing ?

new AgentBuilder.Default().disableClassFormatChanges().with(RedefinitionStrategy.RETRANSFORMATION).with(new Adapter() {
  @Override
  public void onError(String typeName, ClassLoader classLoader, JavaModule module, boolean loaded, Throwable throwable) {
    System.out.println("ERROR");
  }

  @Override
  public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, JavaModule module, boolean loaded, DynamicType dynamicType) {
    System.out.println("TRANFORMED"); 
  }
});

rupinder10 avatar Oct 19 '23 16:10 rupinder10

I would need a reproducer as this looks right. Did you try overriding the other methods, too.

raphw avatar Oct 19 '23 17:10 raphw

I didnt do the others but let me try and confirm

rupinder10 avatar Oct 19 '23 17:10 rupinder10

It may have been a user error. There was an obfuscator involved and one of the classes got obfuscated. False alarm.

I do have a question though, Is there no way to hit a listener method only if the class was transformed ? Looks onTransformation just gets called irrespective

rupinder10 avatar Oct 19 '23 18:10 rupinder10

If a class is not transformed, onIgnore is invoked.

raphw avatar Oct 19 '23 19:10 raphw

I may have my logic wrong then. I am basically calling the transformer as above and then in the transformer getting the advice. If the advice is not present I just return otherwise use the advice to transform. So for me what is happening is that the onIgnore is called for every class in the classpath. is there a better way to specify only a handful of classes to consider ?

rupinder10 avatar Oct 19 '23 19:10 rupinder10

@raphw Here is the code I am using:

agentBuilder.type(ElementMatchers.namedOneOf(classes)).transform(transformer);

I have about 10 classes in the classes array. So what I found is that the onIgnore is invoked for all classes not in the array. And the onTransformation is called for all the 10 classes in this array.

What I am looking for is a way to identify which ones out of the 10 actually got transformed and which one went through the transformation but did not change because one of the method matchers did not match. Is this possible ? One way I got it working is to check and the length of the before and after bytecode to see if it really changed. Is that the best or is there a better way ?

rupinder10 avatar Oct 21 '23 14:10 rupinder10

There's no way to detect this today, but I might co sider it in the future as an internal optinization.

raphw avatar Oct 23 '23 18:10 raphw

There's no way to detect this today, but I might co sider it in the future as an internal optinization.

Maybe bytbuddy can provide a strategy without changing the original code, cancel all external packaging, retain only bytbuddy's instrumentation capabilities, and use a wrap to proxy the transform process. This idea is similar to the interceptor, but the interceptor It needs to be specified by the user. There is only the instrumentation process between interceptors without any redundant matching. We are doing this, but I hope bytebuddy can consider providing a low-level access method, because sometimes it is indeed There are more detailed requirements, which may not be satisfied by bytebuddy matching mechanism. Moreover, bytebuddy’s current matching has several problems

1057105012 avatar Nov 03 '23 01:11 1057105012

There's no way to detect this today, but I might co sider it in the future as an internal optinization.

In complex environments, java instrumentation may encounter strange errors.

  1. Start the security manager
  2. Customized jdk
  3. The class loader has been completely rewritten and violates the basic mode
  4. There are multiple complex matches in the matching process, and when ignore is triggered, it cannot be determined in time which match caused it, and the circulation process is too convoluted. Because bytebuddy's matching relies on the merging and packaging of matchers, and relying on this packaging cannot be taken To get the complete context, if you want to get the complete context, you must construct the typeDescription object, which leads to a problem. If I want to build a cache, it will cause me to need to span multiple matchers, or search for bytebuddy The api constructs a typeDescription because bytebuddy does not directly provide this function, but this leads to a problem. Since the one I constructed myself cannot be passed down, I can only construct the typeDescription twice.
  5. The above scenario is because we consider the performance issues of interface instrumentation and need to make a string cache collection, with key as a subclass and value as a parent class collection. All matching depends entirely on the generated cache class diagram, and the cache class diagram does not When relevant data exists, bytebuddy's api is called to generate data filling. The current bytebuddy is not well supported. I need to operate back and forth between multiple matchers, which always feels weird because I cannot see the complete context. , unless I accept the redundant construction brought about by bytebuddy's default matching mechanism, but this goes against my original intention of optimizing

1057105012 avatar Nov 03 '23 01:11 1057105012

There's no way to detect this today, but I might co sider it in the future as an internal optinization.

The purpose of this requirement is to erase the complete byte reference of the class so that it can be quickly released if it cannot be matched.

1057105012 avatar Nov 03 '23 01:11 1057105012