【问题标题】:Can I create a ByteBuddy instrumented type with a private static final MethodHandle field in it?我可以创建一个带有私有静态最终 MethodHandle 字段的 ByteBuddy 检测类型吗?
【发布时间】:2020-08-13 15:25:36
【问题描述】:

我过去曾问过similar question,但未能成功(不清楚是否可行)。

现在我发现自己处于需要创建类型为MethodHandleprivate static final 字段的情况下。

当然,在 Java 中,我可以这样做:

private static final MethodHandle mh = goGetMethodHandle();

...其中goGetMethodHandle() 是一个static 函数,它返回我需要的MethodHandle

或者,等效地,我可以这样做:

private static final MethodHandle mh;
static {
  mh = goGetMethodHandle();
}

我不确定 ByteBuddy 配方应该在这里。

【问题讨论】:

    标签: byte-buddy


    【解决方案1】:

    使用 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")))
    

    【讨论】:

    • 哦; stackoverflow.com/a/61244544/208288 给我的印象是 private static final 字段需要潜在字段描述。
    • 以前是这样,但四年来发生了很多事情,所以这是一个更可取的选择。
    • 太棒了;谢谢;潜在的建议是今年四月你提出的。不过,我同意你上面的食谱更简单;再次感谢。如果我想完全避免反射,我认为潜在版本仍然是要走的路吗?只是想理解。
    • 2016 年 4 月,不是吗?
    • 否;也许 StackOverflow 对你来说表现得很奇怪? stackoverflow.com/a/61244544/208288 显示您于 2020 年 4 月 16 日回答。无论如何,我知道您在 StackOverflow 上非常活跃,因此很容易错过/忘记。再次感谢。
    【解决方案2】:

    这行得通,但它吓死我了:

      // 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 的方式似乎很疯狂。有没有我想念的更短的方法?

    【讨论】:

      猜你喜欢
      • 2012-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-20
      • 2015-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多