I am using Byte-Buddy to dynamically generate implementations of Java interface methods, and to delegate the calls to these methods to a single method of an existing proxy object.
The first version was inspired by How to create a dynamic proxy using ByteBuddy
It uses a Reflection InvocationHandler
i.e. the concrete proxy class:
- implements the interface
InvocationHandler
- overrides the method
invoke()
This works fine.
Then re-reading the Byte-Buddy readme on Github I discovered an alternative version using MethodDelegation
to a "GeneralInterceptor".
i.e. the concrete proxy class:
- has a method marked with the
RuntimeType
annotation.
This also works fine!
The code snippets below demonstrate both techniques.
Class<? extends Object> clazz = new ByteBuddy()
.subclass(serviceSuperClass)
.name(className)
// use a Reflection InvocationHander for the methods of serviceInterfaceOne
.implement(serviceInterfaceOne)
.defineField(invocationHandler, MyProxy.class, Visibility.PUBLIC)
.method(isDeclaredBy(serviceInterfaceOne))
.intercept(InvocationHandlerAdapter.toField(invocationHandler))
// use a Byte-Buddy "GeneralInterceptor" for the methods of serviceInterfaceTwo
.implement(serviceInterfaceTwo)
.defineField(generalInterceptor, MyProxy.class, Visibility.PUBLIC)
.method(isDeclaredBy(serviceInterfaceTwo))
.intercept(MethodDelegation.toField(generalInterceptor))
//
.make ()
.load(classLoader)
.getLoaded();
public class MyProxy implements InvocationHandler {
@Override
public Object invoke(Object serviceImpl, Method method, Object[] args) throws Throwable {
return null;
}
@RuntimeType
public Object intercept(@AllArguments Object[] allArguments,
@Origin Method method) {
return null;
}
}
From a high-level point-of-view both techniques allow me to do the same thing:
i.e. intercept the given dynamically created methods to an existing concrete method.
Both solutions are elegant, and the amount of code required is similar.
The question is: is there any reason to prefer the one over the other? e.g. Performance? Functionality?