A ScopedValue must be accessible within the functional task where it is bound. Creating a new instance directly inside a ScopedValue.where() call makes the key unreachable, as there is no variable name to reference when calling .get().

Why is this an issue?

The primary purpose of a ScopedValue is to provide a way to share data without passing it as method arguments. To retrieve the value using .get(), you must have access to the ScopedValue instance (the key).

If a ScopedValue is instantiated anonymously within the .where() method, it is "lost" immediately after the binding is created. The code inside the Runnable or Callable has no way to reference that specific instance to retrieve the associated value, rendering the scoped value useless.

How to fix it

Assign the ScopedValue instance to a stable reference — typically a static final field — before using it in a binding. This allows different parts of the code to refer to the same key to set and retrieve values.

Code examples

Noncompliant code example

public class Renderer {

  public void process() {
    // Noncompliant: The ScopedValue instance is anonymous and unreachable inside the run method
    ScopedValue.where(ScopedValue.newInstance(), "DARK").run(() -> {
        render();
    });
  }

  void render() {
    // There is no way to call .get() here because the key is unknown
  }

}

Compliant solution

public class Renderer {

  // Compliant: The ScopedValue is assigned to a constant that can be referenced elsewhere
  private static final ScopedValue<String> THEME = ScopedValue.newInstance();

  public void process() {
    ScopedValue.where(THEME, "DARK").run(() -> {
        render();
    });
  }

  void render() {
    System.out.println("Theme is: " + THEME.get());
  }

}

Resources

Documentation