Package: org.apache.groovy.runtime.async

## [Java] Class ScopedLocal<T>

- org.apache.groovy.runtime.async.ScopedLocal

-     public abstract class ScopedLocal<T>
      extends Object

  A thread-scoped value holder that abstracts over ThreadLocal (JDK < 25) and `java.lang.ScopedValue` (JDK 25+), presenting a unified API modelled after `ScopedValue`.

  ## Backend selection

  On JDK 25+, where finalized `java.lang.ScopedValue` is available, this class delegates to the `ScopedValue` API. On earlier JDK versions it falls back to a conventional `ThreadLocal` with save-and-restore semantics.

  ## API overview

  The API mirrors the main `ScopedValue` operations:

  - get(), orElse(Object), orElseThrow(Supplier), isBound() — query the current binding.
  - where(ScopedLocal, Object) — create a Carrier that can bind one or more values for a scoped execution.
  - Carrier.run, Carrier.call — execute code with the bindings active.

  ## Usage

      private static final ScopedLocal<String> REQUEST_ID =
               ScopedLocal.newInstance();

       ScopedLocal.where(REQUEST_ID, "req-42").run(() -> {
           assert "req-42".equals(REQUEST_ID.get());
       });

       ScopedLocal.where(REQUEST_ID, "req-1")
               .where(TENANT_ID, "acme")
               .call(() -> handleRequest());

       String result = REQUEST_ID.where("req-7", () -> process());

       private static final ScopedLocal<MyCtx> CTX =
               ScopedLocal.withInitial(MyCtx::new);

  Type Parameters:
    `T` - the type of the scoped value
  Since:
    6.0.0

- - ### Nested Class Summary

    Nested classes
    Modifiers | Name | Description
    --- | --- | ---
    `static class` | `ScopedLocal.Carrier` | An immutable set of scoped-local bindings that can be applied atomically for the duration of a Runnable or Supplier.

  - ### Methods Summary

    Methods
    Type Params | Return Type | Name and description
    --- | --- | ---
    `` | `public abstract T` | `get()` Returns the value bound to this scoped-local on the current thread.
    `` | `public abstract boolean` | `isBound()` Returns `true` if an explicit binding is active or an initial supplier is configured.
    `<T>` | `public static ScopedLocal<T>` | `newInstance()` Creates a new `ScopedLocal` with no initial value.
    `` | `public abstract T` | `orElse(T other)` Returns the value bound to this scoped-local, or `other` if no binding is active and no initial supplier is configured.
    `<X extends Throwable>` | `public abstract T` | `orElseThrow(Supplier<? extends X> exceptionSupplier)` Returns the value bound to this scoped-local if available, otherwise throws an exception produced by the `exceptionSupplier`.
    `<T>` | `public static ScopedLocal.Carrier` | `where(ScopedLocal<T> key, T value)` Creates a Carrier that binds `key` to `value`.
    `<R>` | `public final R` | `where(T value, Supplier<R> supplier)` Binds this scoped-local to `value` for the duration of the supplier, then restores the previous binding.
    `` | `public final void` | `where(T value, Runnable action)` Binds this scoped-local to `value` for the duration of the action, then restores the previous binding.
    `<T>` | `public static ScopedLocal<T>` | `withInitial(Supplier<? extends T> initialSupplier)` Creates a new `ScopedLocal` whose get() method returns a lazily initialized default when no explicit binding exists.

  - ### Inherited Methods Summary

    Inherited Methods
    Methods inherited from class | Name
    --- | ---
    `class Object` | `equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait`

- - ### Method Detail

    - #### public abstract T get()

      Returns the value bound to this scoped-local on the current thread.

      throws:
        NoSuchElementException if no value is bound and no initial supplier was provided
      Returns:
        the current value

    - #### public abstract boolean isBound()

      Returns `true` if an explicit binding is active or an initial supplier is configured.

      Returns:
        whether a value is available via get()

    - #### <T> public static ScopedLocal<T> newInstance()

      Creates a new `ScopedLocal` with no initial value.

      Type Parameters:
        `T` - the value type
      Returns:
        a new unbound scoped-local instance

    - #### public abstract T orElse(T other)

      Returns the value bound to this scoped-local, or `other` if no binding is active and no initial supplier is configured.

      Parameters:
        `other` - the fallback value
      Returns:
        the current value or `other`

    - #### <X extends Throwable> public abstract T orElseThrow(Supplier<? extends X> exceptionSupplier)

      Returns the value bound to this scoped-local if available, otherwise throws an exception produced by the `exceptionSupplier`.

      If an initial supplier is configured (via withInitial(Supplier)), this method returns the initial value rather than throwing.

      throws:
        X if no value is bound and no initial supplier is configured
      throws:
        NullPointerException if `exceptionSupplier` is `null`
      Type Parameters:
        `X` - the type of the exception to throw if not bound
      Parameters:
        `exceptionSupplier` - a supplier that produces the exception to throw; must not be `null`
      Returns:
        the current value

    - #### <T> public static ScopedLocal.Carrier where(ScopedLocal<T> key, T value)

      Creates a Carrier that binds `key` to `value`. The binding takes effect when Carrier.run or Carrier.call is invoked.

      Type Parameters:
        `T` - the value type
      Parameters:
        `key` - the scoped-local to bind
        `value` - the value to bind; may be `null`
      Returns:
        a carrier holding the binding

    - #### <R> public final R where(T value, Supplier<R> supplier)

      Binds this scoped-local to `value` for the duration of the supplier, then restores the previous binding.

      Type Parameters:
        `R` - the result type
      Parameters:
        `value` - the value to bind; may be `null`
        `supplier` - the action to execute with the binding active
      Returns:
        the supplier's result

    - #### public final void where(T value, Runnable action)

      Binds this scoped-local to `value` for the duration of the action, then restores the previous binding.

      Parameters:
        `value` - the value to bind; may be `null`
        `action` - the action to execute with the binding active

    - #### <T> public static ScopedLocal<T> withInitial(Supplier<? extends T> initialSupplier)

      Creates a new `ScopedLocal` whose get() method returns a lazily initialized default when no explicit binding exists. The supplier is invoked at most once per thread and the result is cached, analogous to ThreadLocal.withInitial.

      Type Parameters:
        `T` - the value type
      Parameters:
        `initialSupplier` - supplies the default value
      Returns:
        a new scoped-local instance with a default supplier