Package org.apache.groovy.runtime.async
Class ScopedLocal<T>
java.lang.Object
org.apache.groovy.runtime.async.ScopedLocal<T>
- Type Parameters:
T- the type of the scoped value
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 aScopedLocal.Carrierthat can bind one or more values for a scoped execution.ScopedLocal.Carrier.run(Runnable),ScopedLocal.Carrier.call(Supplier)— 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);
- Since:
- 6.0.0
-
Nested Class Summary
Nested ClassesModifier and TypeClassDescriptionstatic final class -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionabstract Tget()Returns the value bound to this scoped-local on the current thread.abstract booleanisBound()Returnstrueif an explicit binding is active or an initial supplier is configured.static <T> ScopedLocal<T>Creates a newScopedLocalwith no initial value.abstract TReturns the value bound to this scoped-local, orotherif no binding is active and no initial supplier is configured.orElseThrow(Supplier<? extends X> exceptionSupplier) Returns the value bound to this scoped-local if available, otherwise throws an exception produced by theexceptionSupplier.static <T> ScopedLocal.Carrierwhere(ScopedLocal<T> key, T value) final voidBinds this scoped-local tovaluefor the duration of the action, then restores the previous binding.final <R> RBinds this scoped-local tovaluefor the duration of the supplier, then restores the previous binding.static <T> ScopedLocal<T>withInitial(Supplier<? extends T> initialSupplier) Creates a newScopedLocalwhoseget()method returns a lazily initialized default when no explicit binding exists.
-
Constructor Details
-
ScopedLocal
public ScopedLocal()
-
-
Method Details
-
newInstance
Creates a newScopedLocalwith no initial value.- Type Parameters:
T- the value type- Returns:
- a new unbound scoped-local instance
-
withInitial
Creates a newScopedLocalwhoseget()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 toThreadLocal.withInitial(Supplier).- Type Parameters:
T- the value type- Parameters:
initialSupplier- supplies the default value- Returns:
- a new scoped-local instance with a default supplier
-
where
Creates aScopedLocal.Carrierthat bindskeytovalue. The binding takes effect whenScopedLocal.Carrier.run(Runnable)orScopedLocal.Carrier.call(Supplier)is invoked.- Type Parameters:
T- the value type- Parameters:
key- the scoped-local to bindvalue- the value to bind; may benull- Returns:
- a carrier holding the binding
-
get
Returns the value bound to this scoped-local on the current thread.- Returns:
- the current value
- Throws:
NoSuchElementException- if no value is bound and no initial supplier was provided
-
orElse
Returns the value bound to this scoped-local, orotherif no binding is active and no initial supplier is configured.- Parameters:
other- the fallback value- Returns:
- the current value or
other
-
orElseThrow
public abstract <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X Returns the value bound to this scoped-local if available, otherwise throws an exception produced by theexceptionSupplier.If an initial supplier is configured (via
withInitial(Supplier)), this method returns the initial value rather than throwing.- 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 benull- Returns:
- the current value
- Throws:
X- if no value is bound and no initial supplier is configuredNullPointerException- ifexceptionSupplierisnull
-
isBound
public abstract boolean isBound()Returnstrueif an explicit binding is active or an initial supplier is configured.- Returns:
- whether a value is available via
get()
-
where
Binds this scoped-local tovaluefor the duration of the supplier, then restores the previous binding.- Type Parameters:
R- the result type- Parameters:
value- the value to bind; may benullsupplier- the action to execute with the binding active- Returns:
- the supplier's result
-
where
Binds this scoped-local tovaluefor the duration of the action, then restores the previous binding.- Parameters:
value- the value to bind; may benullaction- the action to execute with the binding active
-