【问题标题】:How do I install and use a constant MethodHandle in ByteBuddy?如何在 ByteBuddy 中安装和使用常量 MethodHandle?
【发布时间】:2021-01-25 12:28:56
【问题描述】:

我在玩support that ByteBuddy has for constant MethodHandles

我正在尝试(有效地)在一个类上查找 MethodHandle,然后从 ByteBuddy 生成的子类中使用它。

(我知道我可以使用静态 MethodHandle 字段和类型初始化器来做到这一点,但我想尝试使用这种常量支持。)

我有一个FieldDescription.Token 代表第一类中的一个字段,还有一个TypeDescription 代表第一类。从这些我可以得到一个像这样的FieldDescription.InDefinedShapenew FieldDescription.Latent(typeDescription, fieldDescriptionToken)。从 那个 我可以得到一个像这样的JavaConstant.MethodHandleJavaConstant.MethodHandle.ofSetter(fieldDescriptionLatent)。这很好用。

然后我这样做:

// Call invokeExact() on the MethodHandle I looked up, but
// call it on that MethodHandle as a constant pool entry.
builder
  .intercept(MethodCall.invoke(INVOKE_EXACT)
             .on(new JavaConstantValue(javaConstantMethodHandle),
                 MethodHandle.class)
             // etc.

通过这样做,我使用了on overload that takes a StackManipulation,在本例中是JavaConstantValue,它包装了JavaConstant,它是JavaConstant.MethodHandle 的超类。如您所见,我试图在此MethodHandle 上调用invokeExact(),其中MethodHandle 希望存储为常量。

我的第一个问题是:这是正确的食谱吗?

接下来,我将使用这个“字段设置器”MethodHandle 在超类中设置的(愚蠢的)字段被命名为fortyTwo,类型为Integer。您可能会猜到我想将其值设置为什么。 ???这一切都很好,显然(还)与 ByteBuddy 没有任何关系,但它会。

一切正常。

当我运行我的代码时,在我有机会做任何事情之前,即在类加载期间,我会为 ByteBuddy 生成的生成子类获得一个 ClassFormatError。该错误抱怨此 子类 已尝试使用无效签名定义字段 (!):

java.lang.ClassFormatError: Field "fortyTwo" in class com/foo/bar/GeneratedSubclassOf$com$foo$bar$Baz$26753A95 has illegal signature "V"

我没有定义这样的字段。超类当然可以(见上文),它的类型,如前所述,是java.lang.Integer。字段的访问级别无关紧要。

我查看了DynamicType.Unloaded 包含的TypeDescription(显然是在加载之前)并且没有fieldTokens,即ByteBuddy 确实没有尝试在子类中实际定义一个字段。看来我正在使用的配方中的某些东西使它看起来像是……呃,验证者?我猜?真的不知道?常量表示的MethodHandle 正试图操纵子类 上的字段,当然不存在这样的字段(我猜“V”是字节码签名对于void,可能是默认值)。

所以我的最后一个问题是:为什么 使用字段设置 MethodHandle 常量使其看起来像 ByteBuddy 正在尝试定义一个字段在这种情况下在子类中?就好像在定义或存储常量时删除了字段的所属类型一样。

我认为这一切都与 ByteBuddy 如何支持常量MethodHandles 有关。难道是 ByteBuddy 在常量池中没有正确表示这种常量MethodHandle?或者这是MethodHandles 本身的某种固有问题(可能只是字段设置)?

我确实注意到there is a reference (indirectly) to void in the ByteBuddy code in question。这对我来说有一定的意义:如果你要合成一个设置字段的方法句柄,那么它的返回类型将是void。不过,我想知道(天真地)这是否实际上是在此处传递的正确类型,或者这是否可能靠近问题所在。

另一方面,似乎为了解析(在这种情况下)是“字段设置器”或a method handle of kinds 1 through 4, inclusiveresolution must proceed according to the JVM's rules of field resolution 的方法句柄常量。这些规则似乎(对于这个天真的读者)indicate that the descriptor used should be the field's descriptor。我认为相反,ByteBuddy is using the descriptor of the synthesized method handle 在这种情况下将是 V(或 void)。我幼稚的阅读使我认为至少在“字段设置器”的情况下,getDescriptor() 的返回值应该是getParameterTypes() 的返回值中存在的唯一参数的类型。

如果我误诊了,我深表歉意;我还在学习。

【问题讨论】:

    标签: java byte-buddy methodhandle


    【解决方案1】:

    为了后代:这原来是 ByteBuddy for which I've submitted a PR 中的一个错误。

    【讨论】:

      猜你喜欢
      • 2021-01-25
      • 2021-07-01
      • 1970-01-01
      • 2019-01-21
      • 2019-03-28
      • 2017-09-25
      • 2023-03-09
      • 1970-01-01
      • 2019-02-05
      相关资源
      最近更新 更多