Skip to content

Commit fb37b33

Browse files
committed
updated for JDK 27 third preview spec
1 parent 22e001d commit fb37b33

3 files changed

Lines changed: 88 additions & 20 deletions

File tree

platform/o.n.jdk.fallback/src/org/netbeans/jdk/fallback/Bundle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
# specific language governing permissions and limitations
1616
# under the License.
1717

18-
OpenIDE-Module-Name=Simple JDK Fallbacks
18+
OpenIDE-Module-Name=Internal JDK Fallbacks
1919
OpenIDE-Module-Display-Category=Libraries
2020
OpenIDE-Module-Short-Description=Provides internal, non-permanent and possibly incomplete fallbacks for JDK APIs\
2121
which are useful for NetBeans but not covered by the minimal run requirements yet.

platform/o.n.jdk.fallback/src/org/netbeans/jdk/fallback/lang/NBLazyConstant.java

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.lang.invoke.MethodHandle;
2222
import java.lang.invoke.MethodHandles;
2323
import java.lang.invoke.MethodType;
24+
import java.util.NoSuchElementException;
2425
import java.util.Objects;
2526
import java.util.function.Supplier;
2627
import java.util.logging.Level;
@@ -29,6 +30,8 @@
2930
/**
3031
* Delegates to JDK's LazyConstant and provides a fallback implementation if not available.
3132
*
33+
* The fallback implementation simulates behavior of the JDk 27 LazyConstant spec.
34+
*
3235
* Internal API, may be removed when no longer needed.
3336
*
3437
* @author mbien
@@ -75,9 +78,6 @@ private NBLazyConstant() {}
7578
@SuppressWarnings("unchecked")
7679
public static <T> Supplier<T> of(Supplier<? extends T> computingFunction) {
7780
Objects.requireNonNull(computingFunction);
78-
if (computingFunction instanceof DoubleCheckedFallback<? extends T> lc) {
79-
return (Supplier<T>) lc;
80-
}
8181
if (lazyConstantFactory != null) {
8282
try {
8383
return (Supplier<T>) lazyConstantFactory.invokeExact(computingFunction);
@@ -91,6 +91,8 @@ public static <T> Supplier<T> of(Supplier<? extends T> computingFunction) {
9191
}
9292
}
9393

94+
/// simmulates JDK 27 spec, 25 and 26 are more permissive
95+
/// and may allow null or error recovery
9496
private static class DoubleCheckedFallback<T> implements Supplier<T> {
9597

9698
private volatile T constant;
@@ -105,12 +107,19 @@ public T get() {
105107
T c = constant;
106108
if (c == null) {
107109
synchronized (this) {
110+
if (factory == null) { // error state due to past supplier failure
111+
throw new NoSuchElementException("Unable to access the constant because an Exception was thrown at initial computation");
112+
}
108113
c = constant;
109114
if (c == null) {
110-
c = factory.get();
111-
Objects.requireNonNull(c);
115+
try {
116+
c = factory.get();
117+
Objects.requireNonNull(c);
118+
} catch (Throwable t) {
119+
factory = null;
120+
throw new NoSuchElementException(t);
121+
}
112122
constant = c;
113-
factory = null;
114123
}
115124
}
116125
}

platform/o.n.jdk.fallback/test/unit/src/org/netbeans/jdk/fallback/lang/NBLazyConstantTest.java

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
*/
1919
package org.netbeans.jdk.fallback.lang;
2020

21+
import java.util.NoSuchElementException;
2122
import java.util.concurrent.atomic.AtomicBoolean;
23+
import java.util.concurrent.atomic.AtomicInteger;
2224
import java.util.concurrent.atomic.AtomicReference;
2325
import java.util.function.Supplier;
2426
import org.junit.Test;
@@ -28,6 +30,9 @@
2830

2931
public class NBLazyConstantTest {
3032

33+
// true if fallback or JDK 27 impl active
34+
private static final boolean JDK27_SPEC = Runtime.version().feature() >= 27 || Runtime.version().feature() < 25;
35+
3136
@Test
3237
public void testFactory() {
3338

@@ -58,29 +63,60 @@ public void testConstant() {
5863
@Test
5964
public void testRequireNPEOnNullResult() {
6065

61-
// StableValue allows null, we use the LazyConstant spec
62-
assumeTrue(Runtime.version().feature() != 25);
66+
// StableValue allows null, we use the LazyConstant JDK 27 spec
67+
// since its the least permissive
68+
assumeTrue("jdk 25 impl supports null", Runtime.version().feature() != 25);
6369

6470
AtomicReference<Object> value = new AtomicReference<>();
71+
AtomicInteger calls = new AtomicInteger();
6572

66-
Supplier<Object> lazy = NBLazyConstant.of(() -> value.get());
73+
Supplier<Object> lazy = NBLazyConstant.of(() -> {
74+
calls.incrementAndGet();
75+
return value.get();
76+
});
6777
assertNotNull(lazy);
6878

6979
try {
7080
lazy.get();
7181
fail();
72-
} catch (NullPointerException good) {}
82+
} catch (NoSuchElementException good) {
83+
assertTrue(JDK27_SPEC);
84+
assertEquals(NullPointerException.class, good.getCause().getClass());
85+
} catch (NullPointerException good) {
86+
assertFalse(JDK27_SPEC);
87+
}
88+
assertEquals(1, calls.get());
7389

7490
try {
7591
lazy.get();
7692
fail();
77-
} catch (NullPointerException stillGood) {}
93+
} catch (NoSuchElementException stillGood) {
94+
assertTrue(JDK27_SPEC);
95+
// no cause anymore
96+
} catch (NullPointerException stillGood) {
97+
assertFalse(JDK27_SPEC);
98+
}
99+
100+
// JDK 25-26 spec has retries, we don't test those since fallback mimics JDK 27
101+
if (Runtime.version().feature() == 26) {
102+
return;
103+
}
104+
105+
assertEquals(1, calls.get());
78106

79107
value.set("good");
80108

81-
// constant can be computed from now on
82-
assertEquals("good", lazy.get());
83-
assertEquals("good", lazy.get());
109+
// JDK 27+ spec -> no recovery from error state
110+
try {
111+
lazy.get();
112+
fail();
113+
} catch (NoSuchElementException stillGood) {
114+
assertTrue(JDK27_SPEC);
115+
} catch (NullPointerException stillGood) {
116+
assertFalse(JDK27_SPEC);
117+
}
118+
assertEquals(1, calls.get());
119+
84120
}
85121

86122
@Test
@@ -100,18 +136,41 @@ public void testExceptionDuringCompute() {
100136
try {
101137
lazy.get();
102138
fail();
103-
} catch (RuntimeException good) {}
139+
} catch (NoSuchElementException good) {
140+
assertTrue(JDK27_SPEC);
141+
assertEquals(RuntimeException.class, good.getCause().getClass());
142+
} catch (RuntimeException good) {
143+
assertFalse(JDK27_SPEC);
144+
assertEquals(RuntimeException.class, good.getClass());
145+
}
104146

105147
try {
106148
lazy.get();
107149
fail();
108-
} catch (RuntimeException stillGood) {}
150+
} catch (NoSuchElementException good) {
151+
assertTrue(JDK27_SPEC);
152+
// no cause anymore
153+
} catch (RuntimeException good) {
154+
assertFalse(JDK27_SPEC);
155+
assertEquals(RuntimeException.class, good.getClass());
156+
}
109157

110158
fail.set(false);
111159

112-
// constant can be computed from now on
113-
assertEquals("good", lazy.get());
114-
assertEquals("good", lazy.get());
160+
// we don't test error recovery of 25 and 26
161+
if (!JDK27_SPEC) {
162+
// assertEquals("good", lazy.get());
163+
// assertEquals("good", lazy.get());
164+
return;
165+
}
166+
167+
try {
168+
lazy.get();
169+
fail();
170+
} catch (RuntimeException stillInFailureState) {
171+
assertEquals(NoSuchElementException.class, stillInFailureState.getClass());
172+
}
173+
115174
}
116175

117176
}

0 commit comments

Comments
 (0)