在字节好友中设置一个instanceField

Set an instanceField in Byte Buddy

我正在尝试了解如何使用 Byte Buddy 设置实例字段的值。文档说:

Always remember to assign a value to this field before calling methods on an instance of such a dynamic class. Otherwise, a method delegation will result in a NullPointerException.

但我在文档或单元测试中没有看到任何关于如何执行此操作的信息。

我的动态class是:

new ByteBuddy().subclass(AbstractService.class)
        .name(serviceName)
        .method(ElementMatchers.named("start").and(
                ElementMatchers.takesArguments(0)))
        .intercept(
                MethodDelegation.toInstanceField(service, "consumer")
                    .filter(ElementMatchers.isAnnotatedWith(Start.class)))
        .method(ElementMatchers.named("stop").and(
                ElementMatchers.takesArguments(0)))
        .intercept(
                MethodDelegation.to(instance).filter(
                        ElementMatchers.isAnnotatedWith(Stop.class)))
        .make();

我看到另一个 post 的答案是拦截任何构造函数并将 @FieldProxyMethodDelegation 一起使用,但我不知道该怎么做。我在 .constructor(ElementMatchers.any()).intercept(...) 的某些变体中尝试的所有结果都会导致:

java.lang.IllegalArgumentException: None of [] allows for delegation from...

基本上,当您使用 MethodDelegation.toInstanceField 时,字节好友会在生成的 class 中添加一个给定名称的字段。在您的情况下,Byte Buddy 添加了一个类型为 service 的字段,名为 "consumer".

您现在需要决定如何为该字段分配值,因为该字段没有值,即在分配之前 null。如果你在这样做之前调用了一个用 @Start 注释的方法,你会遇到 NullPointerException.

分配字段的最简单方法是反射。一种类型安全的替代方法是实现一些接口

interface SetterIFace {
  void setConsumer(MyType myType);
}

鉴于您的 service 类型是 Class<MyType>。然后您可以添加:

.implement(SetterIFace.class).intercept(FieldAccessor.ofBeanProperty())

MethodDelegation.

中定义相关字段后,SetterIFace 作为相关字段的 setter 实施