如何将构造函数参数绑定到实例字段?

时间:2016-10-28 21:54:57

标签: java byte-buddy

是否可以在类上创建新的final字段并创建一个构造函数,其参数设置为类实例化时的最终字段?我尝试了几种方法并搜索了答案,但没有找到如何做到的示例。

我现在拥有的:

Class proxyClass = new ByteBuddy().subclass(Object.class).implement((Type[]) interfaces)
                        .defineField("dispatcherInvocationHandler", ByteBuddyDispatcherInvocationHandler.class, Modifier.PRIVATE + Modifier.FINAL)
                        .defineConstructor(Modifier.PUBLIC)
                        .withParameter(ByteBuddyDispatcherInvocationHandler.class)
                        .intercept(MethodCall.invokeSuper().andThen(/* copy argument to field */))
                        .method(ElementMatchers.any())
                        .intercept(InvocationHandlerAdapter.toField("dispatcherInvocationHandler"))
                        .make()
                        .load(BytebuddyProxyGenerator.class.getClassLoader())
                        .getLoaded();

我不想公开场,我不想用setter / getter创建属性。我想最终得到类似的东西:

public class DontCare {
    private final ByteBuddyDispatcherInvocationHandler dispatcherInvocationHandler;

    public DontCare(ByteBuddyDispatcherInvocationHandler arg) {
       super();
       this.dispatcherInvocationHandler = arg;
    }
}

有什么简单的方法可以做到这一点吗?

已于2016年10月31日更新

最后,我在Rafael和ByteBuddy库的1.5.2版本的帮助下完成了它。工作代码是这样的:

Class proxyClass = new ByteBuddy().subclass(Object.class).implement((Type[]) interfaces)
                        .defineField("dispatcherInvocationHandler", ByteBuddyDispatcherInvocationHandler.class, Modifier.PRIVATE + Modifier.FINAL)
                        .defineConstructor(Modifier.PUBLIC)
                        .withParameter(ByteBuddyDispatcherInvocationHandler.class)
                        .intercept(
                                MethodCall.invoke(Object.class.getConstructor())
                                        .onSuper()
                                        .andThen(
                                                FieldAccessor.ofField("dispatcherInvocationHandler")
                                                        .setsArgumentAt(0)
                                        )
                        )
                        .method(ElementMatchers.any())
                        .intercept(InvocationHandlerAdapter.toField("dispatcherInvocationHandler"))
                        .make()
                        .load(ByteBuddyProxyGenerator.class.getClassLoader())
                        .getLoaded();

1 个答案:

答案 0 :(得分:2)

不幸的是,目前没有好办法。然而,我确实将此作为重构FieldAccessor实现的灵感,现在允许您执行以下操作:

builder.defineField("desiredField", 
          DispatcherInvocationHandler.class, 
          Visibility.PRIVATE, FieldManifestation.FINAL)
       .defineConstructor(Visibility.PUBLIC)
       .withParameters(String.class)
       .intercept(MethodCall.invokeSuper() // Given such a constructor exists
         .andThen(FieldAccessor.ofField("desiredField").setsArgumentAt(0)))
       .make()
       .load(BytebuddyProxyGenerator.class.getClassLoader())
       .getLoaded();

当您定义这样一个显式设置器时,检测器本身也可以链接。因此,您可以设置多个字段,例如:

FieldAccessor.ofField("foo")
             .setsArgumentAt(0)
             .andThen(FieldAccessor.ofField("bar").setsArgumentAt(1));

通过上面的实现,构造函数(或任何方法)的实现类似于:

class Sample {
  Object foo, bar;
  Sample(Object a1, Object a2) {
    foo = a1;
    bar = a2;
  }
}

此附加API随Byte Buddy 1.5.2发布。