Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 6 additions & 10 deletions src/java.base/share/classes/java/lang/ScopedValue.java
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It occurred to me that ScopedValue.NEW_THREAD_BINDINGS can be made package‑private and used in Thread, removing duplication in Thread.NEW_THREAD_BINDINGS.


This was done this way back when ScopedValue lived under the jdk.incubator.* package tree.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be better not change that in this PR, as this PR is about making the feature permanent.

Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020, 2022, Red Hat Inc.
* Copyright (c) 2020, 2025, Red Hat Inc.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -34,7 +34,6 @@
import java.util.function.Supplier;
import jdk.internal.access.JavaUtilConcurrentTLRAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.javac.PreviewFeature;
import jdk.internal.vm.annotation.ForceInline;
import jdk.internal.vm.annotation.Hidden;
import jdk.internal.vm.ScopedValueContainer;
Expand Down Expand Up @@ -237,9 +236,8 @@
* have to be regenerated after a blocking operation.
*
* @param <T> the type of the value
* @since 21
* @since 25
*/
@PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES)
public final class ScopedValue<T> {
private final int hash;

Expand Down Expand Up @@ -310,9 +308,8 @@ Object find(ScopedValue<?> key) {
* <p> Unless otherwise specified, passing a {@code null} argument to a method in
* this class will cause a {@link NullPointerException} to be thrown.
*
* @since 21
* @since 25
*/
@PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES)
public static final class Carrier {
// Bit masks: a 1 in position n indicates that this set of bound values
// hits that slot in the cache.
Expand Down Expand Up @@ -413,7 +410,6 @@ public <T> T get(ScopedValue<T> key) {
* @return the result
* @throws StructureViolationException if a structure violation is detected
* @throws X if {@code op} completes with an exception
* @since 23
*/
public <R, X extends Throwable> R call(CallableOp<? extends R, X> op) throws X {
Objects.requireNonNull(op);
Expand Down Expand Up @@ -497,9 +493,8 @@ private void runWith(Snapshot newSnapshot, Runnable op) {
*
* @param <T> result type of the operation
* @param <X> type of the exception thrown by the operation
* @since 23
* @since 25
*/
@PreviewFeature(feature = PreviewFeature.Feature.SCOPED_VALUES)
@FunctionalInterface
public interface CallableOp<T, X extends Throwable> {
/**
Expand Down Expand Up @@ -612,10 +607,11 @@ private Object findBinding() {
* Returns the value of this scoped value if bound in the current thread, otherwise
* returns {@code other}.
*
* @param other the value to return if not bound, can be {@code null}
* @param other the value to return if not bound
* @return the value of the scoped value if bound, otherwise {@code other}
*/
public T orElse(T other) {
Objects.requireNonNull(other);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the NPE be specified in the Javadoc?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the class specification, right above the API notes:

 * <p> Unless otherwise specified, passing a {@code null} argument to a method in this
 * class will cause a {@link NullPointerException} to be thrown.

Object obj = findBinding();
if (obj != Snapshot.NIL) {
@SuppressWarnings("unchecked")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ public static Subject getSubject(final AccessControlContext acc) {
* @since 18
*/
public static Subject current() {
return SCOPED_SUBJECT.orElse(null);
return SCOPED_SUBJECT.isBound() ? SCOPED_SUBJECT.get() : null;
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ public enum Feature {

//---
IMPLICIT_CLASSES, //to be removed when boot JDK is 25
@JEP(number=487, title="Scoped Values", status="Fourth Preview")
SCOPED_VALUES,
@JEP(number=505, title="Structured Concurrency", status="Fifth Preview")
STRUCTURED_CONCURRENCY,
Expand Down
1 change: 0 additions & 1 deletion test/jdk/java/lang/ScopedValue/ManyBindings.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
/*
* @test
* @summary Stress test ScopedValue with many bindings and rebindings
* @enablePreview
* @library /test/lib
* @key randomness
* @run junit ManyBindings
Expand Down
6 changes: 2 additions & 4 deletions test/jdk/java/lang/ScopedValue/ScopedValueAPI.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@
/*
* @test
* @summary Test ScopedValue API
* @enablePreview
* @run junit ScopedValueAPI
*/

Expand Down Expand Up @@ -175,18 +174,15 @@ void testIsBound(ThreadFactory factory) throws Exception {
void testOrElse(ThreadFactory factory) throws Exception {
test(factory, () -> {
ScopedValue<String> name = ScopedValue.newInstance();
assertNull(name.orElse(null));
assertEquals("default", name.orElse("default"));

// where
ScopedValue.where(name, "duke").run(() -> {
assertEquals("duke", name.orElse(null));
assertEquals("duke", name.orElse("default"));
});

// callWhere
ScopedValue.where(name, "duke").call(() -> {
assertEquals("duke", name.orElse(null));
assertEquals("duke", name.orElse("default"));
return null;
});
Expand Down Expand Up @@ -416,13 +412,15 @@ void testNullPointerException() {
assertThrows(NullPointerException.class, () -> ScopedValue.where(null, "duke").call(() -> ""));
assertThrows(NullPointerException.class, () -> ScopedValue.where(name, "duke").call(null));

assertThrows(NullPointerException.class, () -> name.orElse(null));
assertThrows(NullPointerException.class, () -> name.orElseThrow(null));

var carrier = ScopedValue.where(name, "duke");
assertThrows(NullPointerException.class, () -> carrier.where(null, "duke"));
assertThrows(NullPointerException.class, () -> carrier.get((ScopedValue<?>)null));
assertThrows(NullPointerException.class, () -> carrier.run(null));
assertThrows(NullPointerException.class, () -> carrier.call(null));
assertThrows(NullPointerException.class, () -> carrier.run(() -> name.orElse(null)));
}

@FunctionalInterface
Expand Down
1 change: 0 additions & 1 deletion test/jdk/java/lang/ScopedValue/UnboundValueAfterOOME.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
/*
* @test
* @bug 8319120
* @enablePreview
* @run main/othervm -Xmx10m UnboundValueAfterOOME
*/
public class UnboundValueAfterOOME {
Expand Down