11
11
package org .junit .platform .engine .support .store ;
12
12
13
13
import static java .util .Comparator .comparing ;
14
+ import static java .util .Objects .requireNonNull ;
14
15
import static org .apiguardian .api .API .Status .EXPERIMENTAL ;
15
16
import static org .junit .platform .commons .util .ReflectionUtils .getWrapperType ;
16
17
import static org .junit .platform .commons .util .ReflectionUtils .isAssignableTo ;
25
26
import java .util .function .Supplier ;
26
27
27
28
import org .apiguardian .api .API ;
29
+ import org .jspecify .annotations .Nullable ;
28
30
import org .junit .platform .commons .util .ExceptionUtils ;
29
31
import org .junit .platform .commons .util .Preconditions ;
30
32
import org .junit .platform .commons .util .UnrecoverableExceptions ;
@@ -51,8 +53,10 @@ public final class NamespacedHierarchicalStore<N> implements AutoCloseable {
51
53
52
54
private final ConcurrentMap <CompositeKey <N >, StoredValue > storedValues = new ConcurrentHashMap <>(4 );
53
55
56
+ @ Nullable
54
57
private final NamespacedHierarchicalStore <N > parentStore ;
55
58
59
+ @ Nullable
56
60
private final CloseAction <N > closeAction ;
57
61
58
62
private volatile boolean closed = false ;
@@ -62,7 +66,7 @@ public final class NamespacedHierarchicalStore<N> implements AutoCloseable {
62
66
*
63
67
* @param parentStore the parent store to use for lookups; may be {@code null}
64
68
*/
65
- public NamespacedHierarchicalStore (NamespacedHierarchicalStore <N > parentStore ) {
69
+ public NamespacedHierarchicalStore (@ Nullable NamespacedHierarchicalStore <N > parentStore ) {
66
70
this (parentStore , null );
67
71
}
68
72
@@ -73,7 +77,8 @@ public NamespacedHierarchicalStore(NamespacedHierarchicalStore<N> parentStore) {
73
77
* @param closeAction the action to be called for each stored value when this
74
78
* store is closed; may be {@code null}
75
79
*/
76
- public NamespacedHierarchicalStore (NamespacedHierarchicalStore <N > parentStore , CloseAction <N > closeAction ) {
80
+ public NamespacedHierarchicalStore (@ Nullable NamespacedHierarchicalStore <N > parentStore ,
81
+ @ Nullable CloseAction <N > closeAction ) {
77
82
this .parentStore = parentStore ;
78
83
this .closeAction = closeAction ;
79
84
}
@@ -152,6 +157,7 @@ public void close() {
152
157
* @throws NamespacedHierarchicalStoreException if this store has already been
153
158
* closed
154
159
*/
160
+ @ Nullable
155
161
public Object get (N namespace , Object key ) {
156
162
StoredValue storedValue = getStoredValue (new CompositeKey <>(namespace , key ));
157
163
return StoredValue .evaluateIfNotNull (storedValue );
@@ -168,6 +174,7 @@ public Object get(N namespace, Object key) {
168
174
* @throws NamespacedHierarchicalStoreException if the stored value cannot
169
175
* be cast to the required type, or if this store has already been closed
170
176
*/
177
+ @ Nullable
171
178
public <T > T get (N namespace , Object key , Class <T > requiredType ) throws NamespacedHierarchicalStoreException {
172
179
Object value = get (namespace , key );
173
180
return castToRequiredType (key , value , requiredType );
@@ -185,13 +192,14 @@ public <T> T get(N namespace, Object key, Class<T> requiredType) throws Namespac
185
192
* @throws NamespacedHierarchicalStoreException if this store has already been
186
193
* closed
187
194
*/
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 ) {
189
197
Preconditions .notNull (defaultCreator , "defaultCreator must not be null" );
190
198
CompositeKey <N > compositeKey = new CompositeKey <>(namespace , key );
191
199
StoredValue storedValue = getStoredValue (compositeKey );
192
200
if (storedValue == null ) {
193
201
storedValue = this .storedValues .computeIfAbsent (compositeKey ,
194
- __ -> storedValue (new MemoizingSupplier (() -> {
202
+ __ -> newStoredValue (new MemoizingSupplier (() -> {
195
203
rejectIfClosed ();
196
204
return defaultCreator .apply (key );
197
205
})));
@@ -213,8 +221,9 @@ public <K, V> Object getOrComputeIfAbsent(N namespace, K key, Function<K, V> def
213
221
* @throws NamespacedHierarchicalStoreException if the stored value cannot
214
222
* be cast to the required type, or if this store has already been closed
215
223
*/
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 {
218
227
219
228
Object value = getOrComputeIfAbsent (namespace , key , defaultCreator );
220
229
return castToRequiredType (key , value , requiredType );
@@ -234,9 +243,10 @@ public <K, V> V getOrComputeIfAbsent(N namespace, K key, Function<K, V> defaultC
234
243
* @throws NamespacedHierarchicalStoreException if an error occurs while
235
244
* storing the value, or if this store has already been closed
236
245
*/
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 {
238
248
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 ));
240
250
return StoredValue .evaluateIfNotNull (oldValue );
241
251
}
242
252
@@ -253,6 +263,7 @@ public Object put(N namespace, Object key, Object value) throws NamespacedHierar
253
263
* @throws NamespacedHierarchicalStoreException if this store has already been
254
264
* closed
255
265
*/
266
+ @ Nullable
256
267
public Object remove (N namespace , Object key ) {
257
268
rejectIfClosed ();
258
269
StoredValue previous = this .storedValues .remove (new CompositeKey <>(namespace , key ));
@@ -273,16 +284,18 @@ public Object remove(N namespace, Object key) {
273
284
* @throws NamespacedHierarchicalStoreException if the stored value cannot
274
285
* be cast to the required type, or if this store has already been closed
275
286
*/
287
+ @ Nullable
276
288
public <T > T remove (N namespace , Object key , Class <T > requiredType ) throws NamespacedHierarchicalStoreException {
277
289
rejectIfClosed ();
278
290
Object value = remove (namespace , key );
279
291
return castToRequiredType (key , value , requiredType );
280
292
}
281
293
282
- private StoredValue storedValue (Supplier <Object > value ) {
294
+ private StoredValue newStoredValue (Supplier <@ Nullable Object > value ) {
283
295
return new StoredValue (this .insertOrderSequence .getAndIncrement (), value );
284
296
}
285
297
298
+ @ Nullable
286
299
private StoredValue getStoredValue (CompositeKey <N > compositeKey ) {
287
300
StoredValue storedValue = this .storedValues .get (compositeKey );
288
301
if (storedValue != null ) {
@@ -294,15 +307,16 @@ private StoredValue getStoredValue(CompositeKey<N> compositeKey) {
294
307
return null ;
295
308
}
296
309
310
+ @ Nullable
297
311
@ 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 ) {
299
313
Preconditions .notNull (requiredType , "requiredType must not be null" );
300
314
if (value == null ) {
301
315
return null ;
302
316
}
303
317
if (isAssignableTo (value , requiredType )) {
304
318
if (requiredType .isPrimitive ()) {
305
- return (T ) getWrapperType (requiredType ).cast (value );
319
+ return (T ) requireNonNull ( getWrapperType (requiredType ) ).cast (value );
306
320
}
307
321
return requiredType .cast (value );
308
322
}
@@ -351,13 +365,14 @@ public int hashCode() {
351
365
private static class StoredValue {
352
366
353
367
private final int order ;
354
- private final Supplier <Object > supplier ;
368
+ private final Supplier <@ Nullable Object > supplier ;
355
369
356
- StoredValue (int order , Supplier <Object > supplier ) {
370
+ StoredValue (int order , Supplier <@ Nullable Object > supplier ) {
357
371
this .order = order ;
358
372
this .supplier = supplier ;
359
373
}
360
374
375
+ @ Nullable
361
376
private <N > EvaluatedValue <N > evaluateSafely (CompositeKey <N > compositeKey ) {
362
377
try {
363
378
return new EvaluatedValue <>(compositeKey , this .order , evaluate ());
@@ -368,11 +383,13 @@ private <N> EvaluatedValue<N> evaluateSafely(CompositeKey<N> compositeKey) {
368
383
}
369
384
}
370
385
386
+ @ Nullable
371
387
private Object evaluate () {
372
388
return this .supplier .get ();
373
389
}
374
390
375
- static Object evaluateIfNotNull (StoredValue value ) {
391
+ @ Nullable
392
+ static Object evaluateIfNotNull (@ Nullable StoredValue value ) {
376
393
return value != null ? value .evaluate () : null ;
377
394
}
378
395
@@ -385,16 +402,20 @@ private static class EvaluatedValue<N> {
385
402
386
403
private final CompositeKey <N > compositeKey ;
387
404
private final int order ;
405
+
406
+ @ Nullable
388
407
private final Object value ;
389
408
390
- private EvaluatedValue (CompositeKey <N > compositeKey , int order , Object value ) {
409
+ private EvaluatedValue (CompositeKey <N > compositeKey , int order , @ Nullable Object value ) {
391
410
this .compositeKey = compositeKey ;
392
411
this .order = order ;
393
412
this .value = value ;
394
413
}
395
414
396
415
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
+ }
398
419
}
399
420
400
421
}
@@ -408,18 +429,21 @@ private void close(CloseAction<N> closeAction) throws Throwable {
408
429
*
409
430
* @see StoredValue
410
431
*/
411
- private static class MemoizingSupplier implements Supplier <Object > {
432
+ private static class MemoizingSupplier implements Supplier <@ Nullable Object > {
412
433
413
434
private static final Object NO_VALUE_SET = new Object ();
414
435
415
- private final Supplier <Object > delegate ;
436
+ private final Supplier <@ Nullable Object > delegate ;
437
+
438
+ @ Nullable
416
439
private volatile Object value = NO_VALUE_SET ;
417
440
418
- private MemoizingSupplier (Supplier <Object > delegate ) {
441
+ private MemoizingSupplier (Supplier <@ Nullable Object > delegate ) {
419
442
this .delegate = delegate ;
420
443
}
421
444
422
445
@ Override
446
+ @ Nullable
423
447
public Object get () {
424
448
if (this .value == NO_VALUE_SET ) {
425
449
computeValue ();
0 commit comments