Reputation: 3728
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
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