byte-buddy
byte-buddy copied to clipboard
How to ignore interfaces and match only based on method names and parameters
Thanks for creating bytebuddy. It's a fantastic library. I am moving a legacy cglib implementation to bytebuddy to work with JDK 17. I am using latest bytebuddy version 1.12.9
There are two classes here: Source and Target. Bytebuddy is used to create proxy for Source and redirect to Target's methods if the Source 's method is abstract
OpenConnection Interface has Method Double open(int i ) => Not implemented anywhere
SmallOpenConnection Interface has below methods Double open(int i ) => Implemented by Target
public abstract class Source implements OpenConnection {} public class Target implements SmallOpenConnection{ public Double open(int i){ return new Double(4); } }
When I call proxy.Open(4), though the method name is same bytebuddy is failing with the below error. The methods belong to different interface but they have same names and parameter types. Is there a way to ignore the interface and use only method name and parameters for matching?
Exception in thread "main" java.lang.ClassCastException: com.bytebuddy.demo.Target cannot be cast to com.bytebuddy.demo.OpenConnection at com.bytebuddy.demo.Source$ByteBuddy$B7CASAjs$auxiliary$X26c7uMO.to(Unknown Source) at com.bytebuddy.demo.Interceptor.log(Interceptor.java:19) at com.bytebuddy.demo.Source$ByteBuddy$B7CASAjs.open(Unknown Source) at com.bytebuddy.demo.Starter.test(Starter.java:23) at com.bytebuddy.demo.Starter.main(Starter.java:16)
T proxy = new ByteBuddy() .subclass(source) .method(isAbstract()) .intercept(MethodDelegation.withDefaultConfiguration() .withBinders(Pipe.Binder.install(Forwarder.class)) .to(new Interceptor(tgt))) .make() .load(getClass().getClassLoader(), ClassLoadingStrategy.Default.INJECTION) .getLoaded().newInstance();
`public class Interceptor {
private final Object adaptee;
public Interceptor(Object adaptee) {
super();
this.adaptee = adaptee;
}
@RuntimeType
public Object log(@Pipe Forwarder<Object, Object> pipe) {
System.out.println("Calling method");
try {
return pipe.to(adaptee);
} finally {
System.out.println("Returned from method");
}
}
} `
Unfortunately, there is nothing ready made, but I would suggest you to get the @Origin Method and resolve the target using reflection and cache it in a concurrent map.
Alternatively, you can write your own binder and register a custom annotation and proxy. Take the pipe binder as an example for it.
Thanks. I am using reflection based interceptor for now
Is there any advantage in performance by having something similar to pipe binder?
It avoids allocation but mostly, in modern JVMs, the overhead is minimal. You might even use method handles to further reduce the overhead.