Skip to content

Commit 3242bf6

Browse files
committed
Make ReflectionSupport.findNestedClasses thread-safe
ReflectionSupport.findNestedClasses(..)` is now thread-safe with regard to cycle detection. Closes #2715
1 parent 7896665 commit 3242bf6

File tree

3 files changed

+13
-8
lines changed

3 files changed

+13
-8
lines changed

documentation/src/docs/asciidoc/release-notes/release-notes-5.8.1.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ GitHub.
2323

2424
==== New Features and Improvements
2525

26-
* ❓
26+
* `ReflectionSupport.findNestedClasses(..)` is now thread-safe with regard to cycle
27+
detection.
2728

2829

2930
[[release-notes-5.8.1-junit-jupiter]]

junit-platform-commons/src/main/java/org/junit/platform/commons/util/ReflectionUtils.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,13 @@
4141
import java.util.Arrays;
4242
import java.util.Collections;
4343
import java.util.HashMap;
44-
import java.util.HashSet;
4544
import java.util.IdentityHashMap;
4645
import java.util.LinkedHashSet;
4746
import java.util.List;
4847
import java.util.Map;
4948
import java.util.Optional;
5049
import java.util.Set;
50+
import java.util.concurrent.ConcurrentHashMap;
5151
import java.util.function.Predicate;
5252
import java.util.regex.Matcher;
5353
import java.util.regex.Pattern;
@@ -130,7 +130,7 @@ public enum HierarchyTraversalMode {
130130
* @since 1.6
131131
* @see #detectInnerClassCycle(Class)
132132
*/
133-
private static final Set<String> noCyclesDetectedCache = new HashSet<>();
133+
private static final Set<String> noCyclesDetectedCache = ConcurrentHashMap.newKeySet();
134134

135135
/**
136136
* Internal cache of common class names mapped to their types.

platform-tests/src/test/java/org/junit/platform/commons/util/ReflectionUtilsTests.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
import java.util.function.Predicate;
4646
import java.util.logging.Level;
4747
import java.util.logging.LogRecord;
48+
import java.util.stream.Stream;
4849

4950
import org.junit.jupiter.api.Nested;
5051
import org.junit.jupiter.api.Test;
@@ -787,11 +788,14 @@ void findNestedClassesWithSeeminglyRecursiveHierarchies() {
787788
*/
788789
@Test
789790
void findNestedClassesWithRecursiveHierarchies() {
790-
assertNestedCycle(OuterClass.class, InnerClass.class, OuterClass.class);
791-
assertNestedCycle(StaticNestedClass.class, InnerClass.class, OuterClass.class);
792-
assertNestedCycle(RecursiveInnerClass.class, OuterClass.class);
793-
assertNestedCycle(RecursiveInnerInnerClass.class, OuterClass.class);
794-
assertNestedCycle(InnerClass.class, RecursiveInnerInnerClass.class, OuterClass.class);
791+
Runnable runnable1 = () -> assertNestedCycle(OuterClass.class, InnerClass.class, OuterClass.class);
792+
Runnable runnable2 = () -> assertNestedCycle(StaticNestedClass.class, InnerClass.class, OuterClass.class);
793+
Runnable runnable3 = () -> assertNestedCycle(RecursiveInnerClass.class, OuterClass.class);
794+
Runnable runnable4 = () -> assertNestedCycle(RecursiveInnerInnerClass.class, OuterClass.class);
795+
Runnable runnable5 = () -> assertNestedCycle(InnerClass.class, RecursiveInnerInnerClass.class,
796+
OuterClass.class);
797+
Stream.of(runnable1, runnable1, runnable1, runnable2, runnable2, runnable2, runnable3, runnable3, runnable3,
798+
runnable4, runnable4, runnable4, runnable5, runnable5, runnable5).parallel().forEach(Runnable::run);
795799
}
796800

797801
private static List<Class<?>> findNestedClasses(Class<?> clazz) {

0 commit comments

Comments
 (0)