Lev Kuznetsov
Lev Kuznetsov

Reputation: 3728

Method delegation with Byte Buddy

I have a problem getting a simple example working with Byte Buddy, here's my code:

import static java.util.Arrays.asList;
import java.util.stream.Stream;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
import net.bytebuddy.implementation.MethodDelegation;

public class Foo {
  public static class Bar {
    public void bar (String s, Integer i) {
      System.out.println ("s:" + s + " i:" + i);
    }
  }
  public static class Baz {
    public void baz (Integer i, String s) {
      System.out.println ("i:" + i + " s:" + s);
    }
  }

  public static void main (String[] args) {
    try {
      Class<?> c = new ByteBuddy ()
        .subclass (Object.class)
        .defineMethod ("bar", Void.class, asList (String.class, Integer.class), 1)
        .intercept (MethodDelegation.to (new Bar ()))
        .defineMethod ("baz", Void.class, asList (Integer.class, String.class), 1)
        .intercept (MethodDelegation.to (new Baz ()))
        .make ()
        .load (Foo.class.getClassLoader (), ClassLoadingStrategy.Default.WRAPPER)
        .getLoaded ();
      Stream.of (c.getDeclaredMethods ()).forEach (System.out::println);
    } catch (Exception e) {
      e.printStackTrace ();
    }
  }
}

Which I would expect to work and forward the calls to the respected interceptor instances, however I get this exception:

java.lang.IllegalArgumentException: None of [protected void java.lang.Object.finalize() throws java.lang.Throwable, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public final void java.lang.Object.wait() throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), protected native java.lang.Object java.lang.Object.clone() throws java.lang.CloneNotSupportedException, public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll(), public void Foo$Bar.bar(java.lang.String,java.lang.Integer)] allows for delegation from public java.lang.Void net.bytebuddy.renamed.java.lang.Object$ByteBuddy$P87HQ3lQ.bar(java.lang.String,java.lang.Integer)
at net.bytebuddy.implementation.bind.MethodDelegationBinder$Processor.process(MethodDelegationBinder.java:881)
at net.bytebuddy.implementation.MethodDelegation$Appender.apply(MethodDelegation.java:1218)
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)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:3193)
at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1481)
at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:234)
at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$AbstractDelegatingBuilder.make(DynamicType.java:2177)
at Foo.main(Foo.java:55)

The weirdest part being at the very end of that exception message:

[...] public void Foo$Bar.bar(java.lang.String,java.lang.Integer)] allows for delegation from public java.lang.Void net.bytebuddy.renamed.java.lang.Object$ByteBuddy$P87HQ3lQ.bar(java.lang.String,java.lang.Integer)

What am I doing wrong?

Upvotes: 4

Views: 4147

Answers (2)

Rafael Winterhalter
Rafael Winterhalter

Reputation: 44032

You are right with your assumption. Byte Buddy cannot assign a void non-type to a Void type. Byte Buddy can however assign null to a reference type from a void method, when you annotated the interceptors with @RuntimeType:

public class Bar {
  @RuntimeType
  public void bar (String s, Integer i) {
    System.out.println ("s:" + s + " i:" + i);
  }
}
public class Baz {
  @RuntimeType
  public void baz (Integer i, String s) {
    System.out.println ("i:" + i + " s:" + s);
  }
}

Upvotes: 3

Lev Kuznetsov
Lev Kuznetsov

Reputation: 3728

As I submitted and looked back at my question I thought the problem may be with the void return as opposed to Void and sure enough, changing the return type on the interceptors worked

Upvotes: 0

Related Questions