我可以创建一个带有 private static final MethodHandle 字段的 ByteBuddy 检测类型吗?
Can I create a ByteBuddy instrumented type with a private static final MethodHandle field in it?
我过去曾问过 similar question 但无法实现(不清楚是否可行)。
现在我发现自己 需要 创建一个 private static final
字段,其类型(在我的例子中)是 MethodHandle
。
在Java中,当然,我可以简单地做:
private static final MethodHandle mh = goGetMethodHandle();
…其中 goGetMethodHandle()
是一个 static
函数,returns 我需要 MethodHandle
。
或者,等价地,我可以这样做:
private static final MethodHandle mh;
static {
mh = goGetMethodHandle();
}
我不确定 ByteBuddy 的配方应该是什么。
这有效,但把我吓死了:
// Excerpt from JUnit Jupiter unit test whose class is named
// TestPrivateStaticFinalFieldInitialization:
@Test
final void testAll() throws Throwable {
final MethodDescription findStaticMethodDescription = new TypeDescription.ForLoadedType(MethodHandles.Lookup.class)
.getDeclaredMethods()
.filter(ElementMatchers.named("findStatic"))
.getOnly();
final MethodDescription methodHandlesLookupMethodDescription = new TypeDescription.ForLoadedType(MethodHandles.class)
.getDeclaredMethods()
.filter(ElementMatchers.named("lookup"))
.getOnly();
final MethodDescription methodTypeMethodTypeMethodDescription = new TypeDescription.ForLoadedType(MethodType.class)
.getDeclaredMethods()
.filter(ElementMatchers.named("methodType")
.and(ElementMatchers.isStatic()
.and(ElementMatchers.takesArguments(Class.class))))
.getOnly();
final ByteBuddy byteBuddy = new ByteBuddy();
DynamicType.Builder<?> builder = byteBuddy.subclass(Object.class);
builder = builder
.defineField("gorp", MethodHandle.class, Visibility.PRIVATE, Ownership.STATIC, SyntheticState.SYNTHETIC, FieldManifestation.FINAL)
.invokable(ElementMatchers.isTypeInitializer())
.intercept(MethodCall.invoke(findStaticMethodDescription)
.onMethodCall(MethodCall.invoke(methodHandlesLookupMethodDescription))
.with(new TypeDescription.ForLoadedType(TestPrivateStaticFinalFieldInitialization.class))
.with("goop")
.withMethodCall(MethodCall.invoke(methodTypeMethodTypeMethodDescription)
.with(new TypeDescription.ForLoadedType(void.class)))
.setsField(new FieldDescription.Latent(builder.toTypeDescription(),
"gorp",
ModifierContributor.Resolver.of(Visibility.PRIVATE,
Ownership.STATIC,
SyntheticState.SYNTHETIC,
FieldManifestation.FINAL).resolve(),
TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(MethodHandle.class),
Collections.emptyList())));
final Class<?> newClass = builder.make().load(Thread.currentThread().getContextClassLoader()).getLoaded();
final Field gorpField = newClass.getDeclaredField("gorp");
gorpField.setAccessible(true);
final MethodHandle methodHandle = (MethodHandle)gorpField.get(null);
assertNotNull(methodHandle);
methodHandle.invokeExact();
}
public static final void goop() {
System.out.println("*** goop");
}
到此结束,您可以在终端上看到*** goop
。
我在这里做的事情有没有可以简化的?
例如,我创建 FieldDescription.Latent
的方式似乎很疯狂。有没有我遗漏的更短的方式?
使用 DSL 可以更轻松地完成您的解决方案:
builder
.defineField("gorp", MethodHandle.class,
Visibility.PRIVATE, Ownership.STATIC, SyntheticState.SYNTHETIC, FieldManifestation.FINAL)
.invokeable(isTypeInitializer())
.intercept(MethodCall.invoke(Some.class.getMethod("goGetMethodHandle")
.setsField(named("gorp")))
我过去曾问过 similar question 但无法实现(不清楚是否可行)。
现在我发现自己 需要 创建一个 private static final
字段,其类型(在我的例子中)是 MethodHandle
。
在Java中,当然,我可以简单地做:
private static final MethodHandle mh = goGetMethodHandle();
…其中 goGetMethodHandle()
是一个 static
函数,returns 我需要 MethodHandle
。
或者,等价地,我可以这样做:
private static final MethodHandle mh;
static {
mh = goGetMethodHandle();
}
我不确定 ByteBuddy 的配方应该是什么。
这有效,但把我吓死了:
// Excerpt from JUnit Jupiter unit test whose class is named
// TestPrivateStaticFinalFieldInitialization:
@Test
final void testAll() throws Throwable {
final MethodDescription findStaticMethodDescription = new TypeDescription.ForLoadedType(MethodHandles.Lookup.class)
.getDeclaredMethods()
.filter(ElementMatchers.named("findStatic"))
.getOnly();
final MethodDescription methodHandlesLookupMethodDescription = new TypeDescription.ForLoadedType(MethodHandles.class)
.getDeclaredMethods()
.filter(ElementMatchers.named("lookup"))
.getOnly();
final MethodDescription methodTypeMethodTypeMethodDescription = new TypeDescription.ForLoadedType(MethodType.class)
.getDeclaredMethods()
.filter(ElementMatchers.named("methodType")
.and(ElementMatchers.isStatic()
.and(ElementMatchers.takesArguments(Class.class))))
.getOnly();
final ByteBuddy byteBuddy = new ByteBuddy();
DynamicType.Builder<?> builder = byteBuddy.subclass(Object.class);
builder = builder
.defineField("gorp", MethodHandle.class, Visibility.PRIVATE, Ownership.STATIC, SyntheticState.SYNTHETIC, FieldManifestation.FINAL)
.invokable(ElementMatchers.isTypeInitializer())
.intercept(MethodCall.invoke(findStaticMethodDescription)
.onMethodCall(MethodCall.invoke(methodHandlesLookupMethodDescription))
.with(new TypeDescription.ForLoadedType(TestPrivateStaticFinalFieldInitialization.class))
.with("goop")
.withMethodCall(MethodCall.invoke(methodTypeMethodTypeMethodDescription)
.with(new TypeDescription.ForLoadedType(void.class)))
.setsField(new FieldDescription.Latent(builder.toTypeDescription(),
"gorp",
ModifierContributor.Resolver.of(Visibility.PRIVATE,
Ownership.STATIC,
SyntheticState.SYNTHETIC,
FieldManifestation.FINAL).resolve(),
TypeDescription.Generic.OfNonGenericType.ForLoadedType.of(MethodHandle.class),
Collections.emptyList())));
final Class<?> newClass = builder.make().load(Thread.currentThread().getContextClassLoader()).getLoaded();
final Field gorpField = newClass.getDeclaredField("gorp");
gorpField.setAccessible(true);
final MethodHandle methodHandle = (MethodHandle)gorpField.get(null);
assertNotNull(methodHandle);
methodHandle.invokeExact();
}
public static final void goop() {
System.out.println("*** goop");
}
到此结束,您可以在终端上看到*** goop
。
我在这里做的事情有没有可以简化的?
例如,我创建 FieldDescription.Latent
的方式似乎很疯狂。有没有我遗漏的更短的方式?
使用 DSL 可以更轻松地完成您的解决方案:
builder
.defineField("gorp", MethodHandle.class,
Visibility.PRIVATE, Ownership.STATIC, SyntheticState.SYNTHETIC, FieldManifestation.FINAL)
.invokeable(isTypeInitializer())
.intercept(MethodCall.invoke(Some.class.getMethod("goGetMethodHandle")
.setsField(named("gorp")))