0

I'm sorry for my English, I'm having trouble with an implementation.

I have an abstract class with only one method that implements an interface

    package br.com.teste;

public abstract class Test implements IDefault
{
    @Override
    public String test1()
    {
        return "Test method Class";
    }
}

I have an interface with the abstract class method

package br.com.teste;

public interface IDefault
{
    public String test1();
}

And I have a second interface that extends to first one and has one more method

package br.com.teste;

public interface ITest extends IDefault
{
    public String test2();
}

Interceptor

package br.com.teste.intercept;

import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import net.bytebuddy.dynamic.TargetType;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.Super;
import net.bytebuddy.implementation.bind.annotation.SuperCall;


public class ProxyInvocationHandler
{
    @RuntimeType
    public static Object intercept(@SuperCall Callable<?> callable, @Super(proxyType = TargetType.class) Object delegate, @Origin Class<?> clazz, @Origin Method method, @AllArguments Object[] args) throws Exception
    {
        System.out.println(method.getName());
        //
        return null;
    }
}

The code i use

package br.com.teste;

import br.com.teste.intercept.ProxyInvocationHandler;
import net.bytebuddy.ByteBuddy;
import net.bytebuddy.ClassFileVersion;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.matcher.ElementMatchers;


public class Main
{
    @SuppressWarnings("unchecked")
    public static void main(String... args)
    {
        try
        {
            ClassLoader classLoader = Main.class.getClassLoader();
            Class<? extends ITest> proxyType = (Class<? extends ITest>) new ByteBuddy(ClassFileVersion.JAVA_V8).subclass(Test.class).implement(ITest.class).method(ElementMatchers.any()).intercept(MethodDelegation.to(ProxyInvocationHandler.class)).make().load(classLoader).getLoaded();
            ITest test = proxyType.newInstance();
            //
            System.out.println(test.test1());
            System.out.println(test.test2());
            //
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

Error

java.lang.IllegalArgumentException: None of [net.bytebuddy.implementation.bind.annotation.TargetMethodAnnotationDrivenBinder$Record@4d8c5c64] allows for delegation from public abstract java.lang.String br.com.teste.ITest.test2()
    at net.bytebuddy.implementation.bind.MethodDelegationBinder$Processor.bind(MethodDelegationBinder.java:827)
    at net.bytebuddy.implementation.MethodDelegation$Appender.apply(MethodDelegation.java:1035)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyCode(TypeWriter.java:614)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod$WithBody.applyBody(TypeWriter.java:603)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$MethodPool$Record$ForDefinedMethod.apply(TypeWriter.java:521)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default$ForCreation.create(TypeWriter.java:4102)
    at net.bytebuddy.dynamic.scaffold.TypeWriter$Default.make(TypeWriter.java:1612)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:174)
    at net.bytebuddy.dynamic.scaffold.subclass.SubclassDynamicTypeBuilder.make(SubclassDynamicTypeBuilder.java:155)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase.make(DynamicType.java:2560)
    at net.bytebuddy.dynamic.DynamicType$Builder$AbstractBase$Delegator.make(DynamicType.java:2662)
    at br.com.teste.Main.main(Main.java:18)
  • Shouldn't `Test` implement `ITest`? The error sounds like `bytebuddy` doesn't find a way to call the method on your instance, which is definitively the case if it doesn't implement the right interface. – BeyelerStudios Jan 29 '17 at 15:18
  • I agree with BeyelerStudios. Your class Test implements IDefault and not ITest. Therefore you only have access to your method test1(). –  Jan 29 '17 at 16:01

4 Answers4

0

Your class Test only implements the IDefault interface which provides method test1. It does not implement the ITest interface, which declares method test2. If it implemented ITest interface, it would automatically mean that it implemented the IDefault as well.

For this reason, you get an exception mentioning that there is no method test2 available in your created subclass of Test.

JChrist
  • 1,734
  • 17
  • 23
0

The application is correct, the byte-ddudy needs to use the methods that are declared in the abstract class. Methods that are just in the byte-duddy interface created blank. As I'm intercepting all the executed methods, for these blank generate a dynamic return. I used cglib for this and it worked.

0

When I remove "@SuperCall" the parameter from the Interceptor method the application works

@RuntimeType
public static Object intercept(@Origin Method method, @AllArguments Object[] args, @Super Object delegate) throws Exception
{
    System.out.println(method.getName());
    //
    return null;
}
0

Your test2 method is abstract down the hierarchy and it cannot be invoked with a super method invocation. Therefore, the @SuperCall annotation cannot be bound to an instance where Byte Buddy rejects the method as a possible binding candidate. You can set the @SuperCall(nullIfImpossible = true) to have null bound to the method or add another interception method with a weaker requirement which Byte Buddy considers its second choice if your method cannot be bound.

Rafael Winterhalter
  • 42,759
  • 13
  • 108
  • 192