ByteBuddy and private static final fields

Boy is this amazingly difficult. I’m writing it here so I won’t forget. I hope this helps someone else. Hopefully, too, there is a less verbose way to accomplish this.

The excerpt below does private static final MethodHandle gorp = MethodHandles.lookup().findStatic(TestPrivateStaticFinalFieldInitialization.class, "goop", MethodType.methodType(void.class)); in ByteBuddy. *** goop shows up on the console at the end. I have a StackOverflow post in case this changes.

Awful formatting courtesy of your friends at WordPress:

// 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");
  }

Advertisement

Author: Laird Nelson

Devoted husband and father; working on Helidon at the intersection of Java, Jakarta EE, architecture, Kubernetes and microservices at Oracle; open source guy; Hammond B3 player and Bainbridge Islander.

%d bloggers like this: