[英]How do I install and use a constant MethodHandle in ByteBuddy?
我正在玩ByteBuddy 對常量MethodHandle
s 的支持。
我試圖(有效地)在一個MethodHandle
上查找 MethodHandle,然后從 ByteBuddy 生成的子類中使用它。
(我知道我可以使用 static MethodHandle
字段和類型初始值設定項來執行此操作,但我想嘗試使用此常量支持。)
我有一個FieldDescription.Token
代表第一個 class 中的一個字段,還有一個TypeDescription
代表第一個 class。從這些我可以得到一個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.
通過這樣做,我使用了帶有 StackManipulation 的on
重載StackManipulation
在這種情況下,它是包裝JavaConstant
JavaConstantValue
它是JavaConstant.MethodHandle
的超類。 如您所見,我正在嘗試在此MethodHandle
上調用invokeExact()
,希望將MethodHandle
存儲為常量。
我的第一個問題是:這是正確的食譜嗎?
接下來,我將使用這個“字段設置器” MethodHandle
在超類中設置的(愚蠢的)字段被命名為fortyTwo
並且類型為Integer
。 您可能會猜到我想將其值設置為什么。 這一切都很好,顯然(還)與 ByteBuddy 沒有任何關系,但它會。
一切都很好。
當我運行我的代碼時,在我有機會做任何事情之前,即在 class 加載期間,我得到了 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 支持常量MethodHandle
的方式有關。 難道是MethodHandle
? 或者這是MethodHandle
本身的某種固有問題(可能只是字段設置)?
我確實注意到在有問題的 ByteBuddy 代碼中有一個(間接地)對void
的引用。 這對我來說有一定的意義:如果您要合成一個設置字段的方法句柄,那么它的返回類型將為void
。 我想知道(天真地)這是否真的是傳遞給這里的正確類型,或者這是否可能接近問題所在。
另一方面,似乎為了解析方法句柄常量(在這種情況下)是“字段設置器”,或1 到 4 種方法句柄,包括在內, 解析必須根據 JVM 的規則進行場分辨率。 這些規則(對於這個天真的讀者來說)似乎表明所使用的描述符應該是字段的描述符。 我認為,ByteBuddy 正在使用合成方法句柄的描述符,在本例中為V
(或void
)。 我天真的閱讀讓我認為至少在“字段設置器”的情況下, getDescriptor()
的返回值應該是getParameterTypes()
的返回值中存在的唯一參數的類型。
如果我誤診了這一點,我深表歉意; 我還在學習。
對於后代:事實證明這是 ByteBuddy中的一個錯誤,我已經為此提交了 PR 。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.