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?
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);
}
}