Skip to content

Commit a1b5879

Browse files
committed
Annotate nullability in org.junit.platform.engine.support.store
1 parent c8429e3 commit a1b5879

File tree

2 files changed

+46
-19
lines changed

2 files changed

+46
-19
lines changed

junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/NamespacedHierarchicalStore.java

Lines changed: 43 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package org.junit.platform.engine.support.store;
1212

1313
import static java.util.Comparator.comparing;
14+
import static java.util.Objects.requireNonNull;
1415
import static org.apiguardian.api.API.Status.EXPERIMENTAL;
1516
import static org.junit.platform.commons.util.ReflectionUtils.getWrapperType;
1617
import static org.junit.platform.commons.util.ReflectionUtils.isAssignableTo;
@@ -25,6 +26,7 @@
2526
import java.util.function.Supplier;
2627

2728
import org.apiguardian.api.API;
29+
import org.jspecify.annotations.Nullable;
2830
import org.junit.platform.commons.util.ExceptionUtils;
2931
import org.junit.platform.commons.util.Preconditions;
3032
import org.junit.platform.commons.util.UnrecoverableExceptions;
@@ -51,8 +53,10 @@ public final class NamespacedHierarchicalStore<N> implements AutoCloseable {
5153

5254
private final ConcurrentMap<CompositeKey<N>, StoredValue> storedValues = new ConcurrentHashMap<>(4);
5355

56+
@Nullable
5457
private final NamespacedHierarchicalStore<N> parentStore;
5558

59+
@Nullable
5660
private final CloseAction<N> closeAction;
5761

5862
private volatile boolean closed = false;
@@ -62,7 +66,7 @@ public final class NamespacedHierarchicalStore<N> implements AutoCloseable {
6266
*
6367
* @param parentStore the parent store to use for lookups; may be {@code null}
6468
*/
65-
public NamespacedHierarchicalStore(NamespacedHierarchicalStore<N> parentStore) {
69+
public NamespacedHierarchicalStore(@Nullable NamespacedHierarchicalStore<N> parentStore) {
6670
this(parentStore, null);
6771
}
6872

@@ -73,7 +77,8 @@ public NamespacedHierarchicalStore(NamespacedHierarchicalStore<N> parentStore) {
7377
* @param closeAction the action to be called for each stored value when this
7478
* store is closed; may be {@code null}
7579
*/
76-
public NamespacedHierarchicalStore(NamespacedHierarchicalStore<N> parentStore, CloseAction<N> closeAction) {
80+
public NamespacedHierarchicalStore(@Nullable NamespacedHierarchicalStore<N> parentStore,
81+
@Nullable CloseAction<N> closeAction) {
7782
this.parentStore = parentStore;
7883
this.closeAction = closeAction;
7984
}
@@ -152,6 +157,7 @@ public void close() {
152157
* @throws NamespacedHierarchicalStoreException if this store has already been
153158
* closed
154159
*/
160+
@Nullable
155161
public Object get(N namespace, Object key) {
156162
StoredValue storedValue = getStoredValue(new CompositeKey<>(namespace, key));
157163
return StoredValue.evaluateIfNotNull(storedValue);
@@ -168,6 +174,7 @@ public Object get(N namespace, Object key) {
168174
* @throws NamespacedHierarchicalStoreException if the stored value cannot
169175
* be cast to the required type, or if this store has already been closed
170176
*/
177+
@Nullable
171178
public <T> T get(N namespace, Object key, Class<T> requiredType) throws NamespacedHierarchicalStoreException {
172179
Object value = get(namespace, key);
173180
return castToRequiredType(key, value, requiredType);
@@ -185,13 +192,14 @@ public <T> T get(N namespace, Object key, Class<T> requiredType) throws Namespac
185192
* @throws NamespacedHierarchicalStoreException if this store has already been
186193
* closed
187194
*/
188-
public <K, V> Object getOrComputeIfAbsent(N namespace, K key, Function<K, V> defaultCreator) {
195+
@Nullable
196+
public <K, V> Object getOrComputeIfAbsent(N namespace, K key, Function<K, @Nullable V> defaultCreator) {
189197
Preconditions.notNull(defaultCreator, "defaultCreator must not be null");
190198
CompositeKey<N> compositeKey = new CompositeKey<>(namespace, key);
191199
StoredValue storedValue = getStoredValue(compositeKey);
192200
if (storedValue == null) {
193201
storedValue = this.storedValues.computeIfAbsent(compositeKey,
194-
__ -> storedValue(new MemoizingSupplier(() -> {
202+
__ -> newStoredValue(new MemoizingSupplier(() -> {
195203
rejectIfClosed();
196204
return defaultCreator.apply(key);
197205
})));
@@ -213,8 +221,9 @@ public <K, V> Object getOrComputeIfAbsent(N namespace, K key, Function<K, V> def
213221
* @throws NamespacedHierarchicalStoreException if the stored value cannot
214222
* be cast to the required type, or if this store has already been closed
215223
*/
216-
public <K, V> V getOrComputeIfAbsent(N namespace, K key, Function<K, V> defaultCreator, Class<V> requiredType)
217-
throws NamespacedHierarchicalStoreException {
224+
@Nullable
225+
public <K, V> V getOrComputeIfAbsent(N namespace, K key, Function<K, @Nullable V> defaultCreator,
226+
Class<V> requiredType) throws NamespacedHierarchicalStoreException {
218227

219228
Object value = getOrComputeIfAbsent(namespace, key, defaultCreator);
220229
return castToRequiredType(key, value, requiredType);
@@ -234,9 +243,10 @@ public <K, V> V getOrComputeIfAbsent(N namespace, K key, Function<K, V> defaultC
234243
* @throws NamespacedHierarchicalStoreException if an error occurs while
235244
* storing the value, or if this store has already been closed
236245
*/
237-
public Object put(N namespace, Object key, Object value) throws NamespacedHierarchicalStoreException {
246+
@Nullable
247+
public Object put(N namespace, Object key, @Nullable Object value) throws NamespacedHierarchicalStoreException {
238248
rejectIfClosed();
239-
StoredValue oldValue = this.storedValues.put(new CompositeKey<>(namespace, key), storedValue(() -> value));
249+
StoredValue oldValue = this.storedValues.put(new CompositeKey<>(namespace, key), newStoredValue(() -> value));
240250
return StoredValue.evaluateIfNotNull(oldValue);
241251
}
242252

@@ -253,6 +263,7 @@ public Object put(N namespace, Object key, Object value) throws NamespacedHierar
253263
* @throws NamespacedHierarchicalStoreException if this store has already been
254264
* closed
255265
*/
266+
@Nullable
256267
public Object remove(N namespace, Object key) {
257268
rejectIfClosed();
258269
StoredValue previous = this.storedValues.remove(new CompositeKey<>(namespace, key));
@@ -273,16 +284,18 @@ public Object remove(N namespace, Object key) {
273284
* @throws NamespacedHierarchicalStoreException if the stored value cannot
274285
* be cast to the required type, or if this store has already been closed
275286
*/
287+
@Nullable
276288
public <T> T remove(N namespace, Object key, Class<T> requiredType) throws NamespacedHierarchicalStoreException {
277289
rejectIfClosed();
278290
Object value = remove(namespace, key);
279291
return castToRequiredType(key, value, requiredType);
280292
}
281293

282-
private StoredValue storedValue(Supplier<Object> value) {
294+
private StoredValue newStoredValue(Supplier<@Nullable Object> value) {
283295
return new StoredValue(this.insertOrderSequence.getAndIncrement(), value);
284296
}
285297

298+
@Nullable
286299
private StoredValue getStoredValue(CompositeKey<N> compositeKey) {
287300
StoredValue storedValue = this.storedValues.get(compositeKey);
288301
if (storedValue != null) {
@@ -294,15 +307,16 @@ private StoredValue getStoredValue(CompositeKey<N> compositeKey) {
294307
return null;
295308
}
296309

310+
@Nullable
297311
@SuppressWarnings("unchecked")
298-
private <T> T castToRequiredType(Object key, Object value, Class<T> requiredType) {
312+
private <T> T castToRequiredType(Object key, @Nullable Object value, Class<T> requiredType) {
299313
Preconditions.notNull(requiredType, "requiredType must not be null");
300314
if (value == null) {
301315
return null;
302316
}
303317
if (isAssignableTo(value, requiredType)) {
304318
if (requiredType.isPrimitive()) {
305-
return (T) getWrapperType(requiredType).cast(value);
319+
return (T) requireNonNull(getWrapperType(requiredType)).cast(value);
306320
}
307321
return requiredType.cast(value);
308322
}
@@ -351,13 +365,14 @@ public int hashCode() {
351365
private static class StoredValue {
352366

353367
private final int order;
354-
private final Supplier<Object> supplier;
368+
private final Supplier<@Nullable Object> supplier;
355369

356-
StoredValue(int order, Supplier<Object> supplier) {
370+
StoredValue(int order, Supplier<@Nullable Object> supplier) {
357371
this.order = order;
358372
this.supplier = supplier;
359373
}
360374

375+
@Nullable
361376
private <N> EvaluatedValue<N> evaluateSafely(CompositeKey<N> compositeKey) {
362377
try {
363378
return new EvaluatedValue<>(compositeKey, this.order, evaluate());
@@ -368,11 +383,13 @@ private <N> EvaluatedValue<N> evaluateSafely(CompositeKey<N> compositeKey) {
368383
}
369384
}
370385

386+
@Nullable
371387
private Object evaluate() {
372388
return this.supplier.get();
373389
}
374390

375-
static Object evaluateIfNotNull(StoredValue value) {
391+
@Nullable
392+
static Object evaluateIfNotNull(@Nullable StoredValue value) {
376393
return value != null ? value.evaluate() : null;
377394
}
378395

@@ -385,16 +402,20 @@ private static class EvaluatedValue<N> {
385402

386403
private final CompositeKey<N> compositeKey;
387404
private final int order;
405+
406+
@Nullable
388407
private final Object value;
389408

390-
private EvaluatedValue(CompositeKey<N> compositeKey, int order, Object value) {
409+
private EvaluatedValue(CompositeKey<N> compositeKey, int order, @Nullable Object value) {
391410
this.compositeKey = compositeKey;
392411
this.order = order;
393412
this.value = value;
394413
}
395414

396415
private void close(CloseAction<N> closeAction) throws Throwable {
397-
closeAction.close(this.compositeKey.namespace, this.compositeKey.key, this.value);
416+
if (this.value != null) {
417+
closeAction.close(this.compositeKey.namespace, this.compositeKey.key, this.value);
418+
}
398419
}
399420

400421
}
@@ -408,18 +429,21 @@ private void close(CloseAction<N> closeAction) throws Throwable {
408429
*
409430
* @see StoredValue
410431
*/
411-
private static class MemoizingSupplier implements Supplier<Object> {
432+
private static class MemoizingSupplier implements Supplier<@Nullable Object> {
412433

413434
private static final Object NO_VALUE_SET = new Object();
414435

415-
private final Supplier<Object> delegate;
436+
private final Supplier<@Nullable Object> delegate;
437+
438+
@Nullable
416439
private volatile Object value = NO_VALUE_SET;
417440

418-
private MemoizingSupplier(Supplier<Object> delegate) {
441+
private MemoizingSupplier(Supplier<@Nullable Object> delegate) {
419442
this.delegate = delegate;
420443
}
421444

422445
@Override
446+
@Nullable
423447
public Object get() {
424448
if (this.value == NO_VALUE_SET) {
425449
computeValue();

junit-platform-engine/src/main/java/org/junit/platform/engine/support/store/package-info.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,7 @@
22
* Reusable data structures for test engines and their extensions.
33
*/
44

5+
@NullMarked
56
package org.junit.platform.engine.support.store;
7+
8+
import org.jspecify.annotations.NullMarked;

0 commit comments

Comments
 (0)