代码之家  ›  专栏  ›  技术社区  ›  Kevin Daly

如何使用Byte Buddy从接口构建Java类的具体实现?

  •  5
  • Kevin Daly  · 技术社区  · 9 年前

    我有一个界面,假设它看起来像这样。

    public interface TestObject {
        String getString();
    
        Long getLong();
    }
    

    我想实际使用ByteBuddy构建这个对象的具体实现。

    这是我试过的。

    public class Runme {
    
        public static void main(String[] args) {
            ByteBuddy bb = new ByteBuddy();
    
            Class<?> clz = bb
                    .subclass(TestObject.class)
          .method(any()).intercept(MethodDelegation.to(Interceptor.class))
                .make()
                .load(Object.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
                .getLoaded();
    
        try {
            Object test = clz.newInstance();
    
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    
    }
    
    public class Interceptor {
    
        public Object intercept(@Origin String method, @AllArguments Object[] args) throws Throwable {
            System.out.println("I have intercepted a call");
    
            return "Hello";
    
        }
    
    }
    

    }

    我收到这个错误

    Exception in thread "main" java.lang.IllegalArgumentException: None of [] allows for delegation from public boolean java.lang.Object.equals(java.lang.Object)
    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 com.meta.testbytebuddy.Runme.main(Runme.java:22)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
    

    我做错了什么++…如果我想实现多个接口呢?

    我使用ByteBuddy进行代码生成。

    1 回复  |  直到 9 年前
        1
  •  4
  •   Rafael Winterhalter    9 年前

    问题是您通过以下方式委托给拦截器的静态方法 MethodDelegation.to(Interceptor.class) 而拦截器类只声明了非静态成员。您可以将拦截器方法声明为 static 或者委托给实例而不是类。我认为前一种方法更合适。

    然而,单靠这一点仍然行不通。您正在返回 Object 在拦截的同时,从拦截器键入 any() 方法这包括您的 TestObject 接口,以及由 对象 ,隐式超类。您可以如下定义拦截器以使类编译,但Byte Buddy会将返回类型强制转换为每个方法的返回类型,这将导致 ClassCastException :

    public class Interceptor {
      @RuntimeType
      public static Object intercept(@Origin String method, @AllArguments Object[] args) {
        System.out.println("I have intercepted a call");
        return "Hello";
      }
    }