Package org.apache.groovy.util

# 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 `Error`s 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:
  - `MethodHandles.Lookup.defineHiddenClass(byte[], boolean, Lookup.ClassOption...)`

- ## Field Summary

  Fields
  Modifier and Type
  Field
  Description
  `static final String`
  `PROPERTY_DISABLE`
  System property that disables hidden-class definitions at run time.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `static boolean`
  `canAttemptPrivateLookup(Class<?> host)`
  Internal policy: whether `privateLookupIn` from this utility into `host` is worth attempting.
  `static boolean`
  `isEnabled()`
  Whether hidden-class definition may be attempted in this process.
  `static Class<?>`
  `tryDefineNestmate(Class<?> host, byte[] bytes, boolean initialize)`
  Best-effort definition of a hidden nestmate of a foreign host.
  `static Class<?>`
  `tryDefineNestmate(MethodHandles.Lookup lookup, byte[] bytes, boolean initialize)`
  Defines `bytes` as a hidden nestmate of `lookup.lookupClass()` with a weak lifecycle.

  ### Methods inherited from class java.lang.Object

  `clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- ## Field Details

  - ### PROPERTY_DISABLE

    public static final String PROPERTY_DISABLE
    System property that disables hidden-class definitions at run time.
    See Also:
      - Constant Field Values

- ## 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