Context propagation mechanism for Java applications that enables carrying scoped values across API boundaries and between threads
—
Core context creation, attachment, and value propagation functionality for maintaining scoped state across API boundaries and thread switches.
The logical root context which is the ultimate ancestor of all contexts. This context is not cancellable and will not cascade cancellation or retain listeners.
/**
* The logical root context which is the ultimate ancestor of all contexts.
* Never assume this is the default context for new threads.
*/
public static final Context ROOT;Returns the context associated with the current scope, never returns null. Will never return CancellableContext even if one is attached.
/**
* Return the context associated with the current scope, will never return null.
* @return The current context, or ROOT if no context is attached
*/
public static Context current();Create typed keys for storing and retrieving values from contexts. Keys use reference equality and provide type safety.
/**
* Create a Key with the given debug name.
* @param debugString Name for debugging purposes, does not impact behavior
* @return New Key instance for the specified type
*/
public static <T> Context.Key<T> key(String debugString);
/**
* Create a Key with the given debug name and default value.
* @param debugString Name for debugging purposes
* @param defaultValue Default value returned when key is not found
* @return New Key instance with default value
*/
public static <T> Context.Key<T> keyWithDefault(String debugString, T defaultValue);Usage Examples:
// Create keys for different types of context data
Context.Key<String> USER_ID_KEY = Context.key("userId");
Context.Key<String> REQUEST_ID_KEY = Context.key("requestId");
Context.Key<Integer> TIMEOUT_KEY = Context.keyWithDefault("timeout", 30);
// Keys are compared by reference equality
Context.Key<String> anotherUserKey = Context.key("userId"); // Different key!
assert USER_ID_KEY != anotherUserKey;Create new contexts with additional key-value pairs. Context objects are immutable, so setting values creates new context instances.
/**
* Create a new context with the given key value set.
* @param key The key to set
* @param value The value to associate with the key
* @return New context instance with the key-value pair
*/
public <V> Context withValue(Context.Key<V> key, V value);
/**
* Create a new context with two key-value pairs.
*/
public <V1, V2> Context withValues(Context.Key<V1> k1, V1 v1, Context.Key<V2> k2, V2 v2);
/**
* Create a new context with three key-value pairs.
*/
public <V1, V2, V3> Context withValues(Context.Key<V1> k1, V1 v1, Context.Key<V2> k2, V2 v2, Context.Key<V3> k3, V3 v3);
/**
* Create a new context with four key-value pairs.
*/
public <V1, V2, V3, V4> Context withValues(Context.Key<V1> k1, V1 v1, Context.Key<V2> k2, V2 v2, Context.Key<V3> k3, V3 v3, Context.Key<V4> k4, V4 v4);Usage Examples:
Context.Key<String> USER_KEY = Context.key("user");
Context.Key<String> ROLE_KEY = Context.key("role");
// Single value
Context withUser = Context.current().withValue(USER_KEY, "alice");
// Multiple values - these are equivalent:
Context withUserAndRole1 = Context.current().withValues(USER_KEY, "alice", ROLE_KEY, "admin");
Context withUserAndRole2 = Context.current()
.withValue(USER_KEY, "alice")
.withValue(ROLE_KEY, "admin");Create a new context which propagates the values of the current context but does not cascade its cancellation.
/**
* Create a new context which propagates values but does not cascade cancellation.
* @return New context that inherits values but not cancellation status
*/
public Context fork();Usage Example:
Context.Key<String> DATA_KEY = Context.key("data");
Context withData = Context.current().withValue(DATA_KEY, "important");
// Create a forked context that won't be cancelled when parent is cancelled
Context forkedContext = withData.fork();
forkedContext.run(() -> {
// This code will continue running even if the parent context is cancelled
String data = DATA_KEY.get(); // "important"
performIndependentTask(data);
});Attach and detach contexts to control the current scope. Every attach() should have a corresponding detach() in the same method.
/**
* Attach this context, entering a new scope within which this context is current.
* @return The previously current context that should be passed to detach()
*/
public Context attach();
/**
* Reverse an attach(), restoring the previous context and exiting the current scope.
* @param toAttach The context that was returned by the corresponding attach() call
*/
public void detach(Context toAttach);Usage Example:
Context.Key<String> USER_KEY = Context.key("user");
Context withUser = Context.current().withValue(USER_KEY, "alice");
// Proper attach/detach pattern
Context previous = withUser.attach();
try {
// Code here runs with withUser as the current context
String user = USER_KEY.get(); // "alice"
processUserRequest(user);
} finally {
withUser.detach(previous);
}Retrieve values from contexts using keys. Keys provide type-safe access to stored values.
public static final class Key<T> {
/**
* Get the value from the current context for this key.
* @return The value associated with this key, or the default value if not found
*/
public T get();
/**
* Get the value from the specified context for this key.
* @param context The context to retrieve the value from
* @return The value associated with this key, or the default value if not found
*/
public T get(Context context);
/**
* String representation of this key (returns the debug name).
* @return The debug name provided when the key was created
*/
public String toString();
}Usage Example:
Context.Key<String> USER_KEY = Context.key("user");
Context.Key<Integer> TIMEOUT_KEY = Context.keyWithDefault("timeout", 30);
Context withValues = Context.current()
.withValue(USER_KEY, "alice")
.withValue(TIMEOUT_KEY, 60);
withValues.run(() -> {
String user = USER_KEY.get(); // "alice"
Integer timeout = TIMEOUT_KEY.get(); // 60
// Can also get from specific context
String userFromContext = USER_KEY.get(withValues); // "alice"
});Install with Tessl CLI
npx tessl i tessl/maven-io-grpc--grpc-context