In Java it is possible to create dynamic proxies using an implementation of InvocationHandler. Despite JVM optimizations, using reflection will always have some overhead invoking a method.
To try to solve this problem, I tried to use ByteBuddy to create the proxy classes at runtime, but the documentation didn't seem clear enough on this aspect.
How do I create a MethodCallProxy in order to forward a method invocation to some class instance?
Edit:
To better clarify my problem, I am providing an example of what I want to achieve:
I am building an RPC system. On each side of a method invocation, I have an interface defining the contract (when both caller/callee are running under the JVM).
@Contract
interface ISomeService {
    fun someMethod(arg0: String, arg1: SomePojo): PojoResult
}
At the call site, I inject a proxy that intercepts all method calls and forwards them to the callee.
ByteBuddy()
    .subclass(Any::class.java)
    .implement(serviceClass)
    // Service contract method delegation
    .method(isDeclaredBy(serviceClass)).intercept(
      MethodDelegation
          .to(ServiceProxyInterceptor())
          .filter(not(isDeclaredBy(Any::class.java)))
    )
    .make()
    .load(this)
    .loaded as Class<T>
And, finally, at the callee, I have several handlers, one for each service method, responsible for unmarshalling the invocation parameters and forwarding them to the service implementation.
@Service
class SomeServiceImpl {
    fun someMethod(arg0: String, arg1: SomePojo): PojoResult {
        // ...
    }
}
I could solve this problem using code generation, but the resulting jar file can become very big. Thus, I want to create a generic version of these handlers and, in each instance, attach a proxy that intercepts every method call to ISomeService and forwards them to SomeServiceImpl.
There are many ways of creating proxy classes in Byte Buddy. The exact way depends on your use-case. The easiest way might be to use the InvocationHandlerAdapter. Given that you want to create a proxy for SomeClass, you can create one using:
Class<? extends SomeClass> proxy = new ByteBuddy()
  .subclass(SomeClass.class)
  .method(ElementMatchers.any())
  .intercept(InvocationHandlerAdapter.of(invocationHandler))
  .make()
  .load(SomeClass.class.getClassLoader());
If you want to create a proxy with a delegate to different instance, you would additionally define a field. This can be done by the following instructions:
Class<? extends SomeClass> proxy = new ByteBuddy()
  .subclass(SomeClass.class)
  .defineField("handler", InvocationHandler.class, Visibility.PUBLIC)
  .method(ElementMatchers.any())
  .intercept(InvocationHandlerAdapter.toField("handler"))
  .make()
  .load(SomeClass.class.getClassLoader());
You would set the above field via reflection or by implementing a setter interface such as for example:
interface HandlerSetter {
  InvocationHandler getHandler();
  void setHandler(InvocationHandler handler);
}
Class<? extends SomeClass> proxy = new ByteBuddy()
  .subclass(SomeClass.class)
  .defineField("handler", InvocationHandler.class, Visibility.PUBLIC)
  .implement(HandlerSetter.class)
  .intercept(FieldAccessor.ofField("handler"))
  .method(ElementMatchers.any())
  .intercept(InvocationHandlerAdapter.toField("handler"))
  .make()
  .load(SomeClass.class.getClassLoader());
You can now instantiate the class and cast the class to the interface for setting the handler.
Beyond the InvocationHandler, there are many other ways to create a proxy. One way would be using MethodDelegation which is more flexible, often faster and allows you to invoke a super method on demand. A forwarding insrumentation can also be applied using a MethodCall or a Forwarding instrumentation. You can find detailed information in the respective classes javadoc.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With