Class HiddenClassDefiner

java.lang.Object
org.apache.groovy.util.HiddenClassDefiner

public final class HiddenClassDefiner extends Object
Central facility for defining hidden classes (JEP 371).

Lookup ownership

MethodHandles.lookup() is caller-sensitive: it returns a full-privilege lookup only for the class that literally contains the call. Production call sites capture a lookup on the intended nest host:


 private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup();
 Class<?> hidden = HiddenClassDefiner.tryDefineNestmate(LOOKUP, bytecode, false);
 
MethodHandles.Lookup.lookupClass() fixes the hidden class's defining loader, package, protection domain, and nest host. Lookups from different runtime classes are not interchangeable as nest hosts even though they share the same module rights (see below).

The lookup captured inside this class is used only as the caller argument to MethodHandles.privateLookupIn(Class, Lookup) for the foreign-host overload — never as a production nest host.

Module rights vs nest host

Every production call site lives in the Groovy runtime, so lookup() always grants the same module-level access. Capturing it in different runtime classes does not open a third-party module that never opened itself to the runtime. What differs is the nest host (package / loader / nest membership), which still matters for unloadability and linkage.

What nestmates cover (modules A / B / C)

With modules A (Java library), B (Groovy program), C (Groovy runtime):

  1. Caller-owned lookup (tryDefineNestmate(Lookup, byte[], boolean)): nestmate of a runtime class. Works when every type named by the bytecode is resolvable from the runtime loader. No private access into foreign modules.
  2. Foreign host (tryDefineNestmate(Class, byte[], boolean)): best-effort privateLookupIn. Succeeds when the host package is open to the runtime (typical for unnamed-module application classes); not for strongly encapsulated packages such as java.lang (String is the counter-example). Callers must handle null and fall back to ClassLoader.defineClass(byte[], int, int).
Nestmates cover C and often open/unnamed B. They do not tunnel private access into A. Visible defineClass is the intentional safety net.

Soft-fail contract

try* methods return null on expected failures (IllegalAccessException, SecurityException, LinkageError, invalid class-file / ASM exceptions, GraalVM UnsupportedFeatureError matched by class name). Other Errors are rethrown.

Enablement

isEnabled() is evaluated per call so -Dgroovy.hidden.classes.disable=true works under native-image build-time init, and is always false when org.graalvm.nativeimage.imagecode=runtime.

Since:
6.0.0
See Also:
  • Field Details

    • PROPERTY_DISABLE

      public static final String PROPERTY_DISABLE
      System property that disables hidden-class definitions at run time.
      See Also:
  • Method Details

    • isEnabled

      public static boolean isEnabled()
      Whether hidden-class definition may be attempted in this process.
      Returns:
      false when the kill switch is set or when running inside a GraalVM native image at run time
    • tryDefineNestmate

      public static Class<?> tryDefineNestmate(MethodHandles.Lookup lookup, byte[] bytes, boolean initialize)
      Defines bytes as a hidden nestmate of lookup.lookupClass() with a weak lifecycle. The class-file package is rewritten to match the lookup class before definition.
      Parameters:
      lookup - full-privilege lookup for the nest host
      bytes - class-file bytes
      initialize - true to run <clinit> immediately
      Returns:
      the hidden class, or null if definition is not possible
    • tryDefineNestmate

      public static Class<?> tryDefineNestmate(Class<?> host, byte[] bytes, boolean initialize)
      Best-effort definition of a hidden nestmate of a foreign host. Uses privateLookupIn from this class; gated by canAttemptPrivateLookup(Class). Not a substitute for a host-owned lookup.
      Parameters:
      host - nest host and class-loader / package donor
      bytes - class-file bytes
      initialize - true to run <clinit> immediately
      Returns:
      the hidden class, or null if private lookup or definition fails
    • canAttemptPrivateLookup

      public static boolean canAttemptPrivateLookup(Class<?> host)
      Internal policy: whether privateLookupIn from this utility into host is worth attempting.

      Returns false for unusable host shapes and for named-module packages that are not open to the Groovy runtime (e.g. String in java.base). A true result does not guarantee success.

      Not a stable user API — for runtime define policy and tests only.

      Parameters:
      host - candidate foreign nest host
      Returns:
      true when a private-lookup attempt is not known to be futile
      Since:
      6.0.0