4

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?

FlyingSheep
  • 804
  • 1
  • 9
  • 20

1 Answers1

1

In this form of usage, there is no real difference other than the delegation can be wired to any (static or non-static) method whereas the invocation handler adapter only bridges implementations for Java's proxy API. It is mainly meant if you already implemented such proxy handlers and want to reuse them with Byte Buddy.

Byte Buddy's handler allows for more flexibility then the handler API which improves performance since you can for example avoid the array boxing if you know what arguments to expect. It also allows for different mechanisms like invoking a default method implementation that the invocation handler API does not support.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192
  • Ok, so in the case where the concrete proxy intercepting the methods is new code, I should prefer the Byte-Buddy "GeneralInterceptor" over the Reflection InvocationHandler. – FlyingSheep Feb 21 '20 at 09:02
  • I'd recommend it if you don't need to use the invocation handler API. Makes it much easier to extend things in the future if you needed additional functionality. – Rafael Winterhalter Feb 21 '20 at 10:20
  • Based on your answer I have just changed my real code to use the Byte-Buddy "GeneralInterceptor" instead of the Reflection InvocationHandler. It just happens that the Reflection approach was the first working soution I found ... Thanks. – FlyingSheep Feb 21 '20 at 10:26
  • One difference between the 2 approaches is that while the InnvocationHandler delegated all source methods regardless of signature to the target invoke() method, The Byte Buddy approach would delegate some source methods to other methods in the proxy class, and not to the expected (by me) intercept() method. To prevent this additional Byte Buddy configuration may be required, as discussed in this Byte Buddy Github issue https://github.com/raphw/byte-buddy/issues/814 – FlyingSheep Feb 24 '20 at 13:23