Lev Kuznetsov
Lev Kuznetsov

Reputation: 3728

Forwarding method calls with Byte Buddy

I'm trying to set up a class with Byte Buddy that implements all the interfaces of a given instance and forwards all calls to that instance, here's my code so far:

import static net.bytebuddy.implementation.Forwarding.to;

static Class<?> save (state) {
  return stream (state.getClass ().getMethods ())
    .filter (m -> isPublic (m.getModifiers ()))
    .reduce ((Builder<?>) new ByteBuddy ().subclass (Object.class)
      .implement (state.getClass ().getInterfaces ()),
             (b, m) -> {
               System.out.println ("Setting up method " + m.getName ());
               return b.define (new ForLoadedMethod (m))
                 .intercept (to (state));
              }, (x, y) -> {
                throw new UnsupportedOperationException ();
              }).make ().load (state.getClass ()
                .getClassLoader (), INJECTION).getLoaded ();
}

public static void main (String[] args) throws Throwable {
  System.out.println ("Saved: " + save (new Integer (1)).newInstance ().toString ());
}

This results in an exception like this:

Exception in thread "main" java.lang.IllegalArgumentException: Cannot forward public boolean net.bytebuddy.renamed.java.lang.Object$ByteBuddy$rwGGy3NN.equals(java.lang.Object) to class java.lang.Integer
at net.bytebuddy.implementation.Forwarding$Appender.apply(Forwarding.java:337)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:510)
at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:444)

I can see the note under Forwarding that for it to work the intercepted method must be defined on a super type of the given delegation target but I'm not sure what that means. If that means I should be subclassing the generated class, what if my target is of a final class? How else can I create a custom implementation that will forward these calls?

Also, since I'm here anyway, how can I specify a generic interface type to implement? Whether it's from a loaded java.lang.reflect.Type or from something I want to create on the fly?

Upvotes: 2

Views: 864

Answers (1)

Rafael Winterhalter
Rafael Winterhalter

Reputation: 44077

The Forwarding implementation works similar to the reflection API where the target needs to be an assignable type. Since you do not subclass Integer (that is impossible anyways), the forwarding delegation fails.

I think that you are looking for the MethodCall delegation where you can name the method you want to call explicitly. Does that work for you?

Finally, implementing generic types is a feature planned for version 0.8. I already made good progress and hope to have a release candidate ready within January 2016. I also plan to revisit the Forwarding delegation, a signature-based invocation should not be too difficult to implement.

Upvotes: 1

Related Questions