4

我正在使用ByteBuddy 对常量MethodHandles的支持。

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

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

我有一个FieldDescription.Token代表头等舱的字段和TypeDescription代表头等舱的字段。从这些我可以得到FieldDescription.InDefinedShape这样的:new FieldDescription.Latent(typeDescription, fieldDescriptionToken)。从那我可以得到一个这样JavaConstant.MethodHandle的:JavaConstant.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带 a 的重载,StackManipulation在这种情况下,JavaConstantValue它包装了 a JavaConstant,它是 的超类JavaConstant.MethodHandle。如您所见,我试图在希望将其存储为常量的地方调用invokeExact()它。MethodHandleMethodHandle

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

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

一切都编译得很好。

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

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

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

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

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

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

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

另一方面,似乎为了解析(在这种情况下)是“字段设置器”的方法句柄常量,或者类型 1 到 4(包括)的方法句柄,解析必须根据 JVM 的规则进行场分辨率。这些规则似乎(对于这个天真的读者)表明使用的描述符应该是字段的描述符。我认为,相反,ByteBuddy正在使用合成方法句柄的描述符,在这种情况下将是V(或void)。我的幼稚阅读使我认为至少在“字段设置器”的情况下,返回值getDescriptor()应该是返回值中存在的唯一参数的类型getParameterTypes().

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

4

1 回答 1

2

对于后代:这原来是 ByteBuddy 中的一个错误,我为此提交了 PR

于 2020-10-14T18:06:10.517 回答