4949import java .util .Optional ;
5050import java .util .Set ;
5151import java .util .concurrent .ConcurrentHashMap ;
52+ import java .util .concurrent .atomic .AtomicBoolean ;
53+ import java .util .function .Consumer ;
5254import java .util .function .Predicate ;
5355import java .util .regex .Matcher ;
5456import java .util .regex .Pattern ;
@@ -1119,10 +1121,7 @@ public static List<Class<?>> findNestedClasses(Class<?> clazz, Predicate<Class<?
11191121 Preconditions .notNull (predicate , "Predicate must not be null" );
11201122
11211123 Set <Class <?>> candidates = new LinkedHashSet <>();
1122- visitNestedClasses (clazz , predicate , nestedClass -> {
1123- candidates .add (nestedClass );
1124- return true ;
1125- });
1124+ visitAllNestedClasses (clazz , predicate , candidates ::add );
11261125 return List .copyOf (candidates );
11271126 }
11281127
@@ -1144,8 +1143,9 @@ public static boolean isNestedClassPresent(Class<?> clazz, Predicate<Class<?>> p
11441143 Preconditions .notNull (clazz , "Class must not be null" );
11451144 Preconditions .notNull (predicate , "Predicate must not be null" );
11461145
1147- boolean visitorWasNotCalled = visitNestedClasses (clazz , predicate , __ -> false );
1148- return !visitorWasNotCalled ;
1146+ AtomicBoolean foundNestedClass = new AtomicBoolean (false );
1147+ visitAllNestedClasses (clazz , predicate , __ -> foundNestedClass .setPlain (true ));
1148+ return foundNestedClass .getPlain ();
11491149 }
11501150
11511151 /**
@@ -1156,10 +1156,15 @@ public static Stream<Class<?>> streamNestedClasses(Class<?> clazz, Predicate<Cla
11561156 return findNestedClasses (clazz , predicate ).stream ();
11571157 }
11581158
1159- private static boolean visitNestedClasses (Class <?> clazz , Predicate <Class <?>> predicate ,
1160- Visitor <Class <?>> visitor ) {
1159+ /**
1160+ * Visit <em>all</em> nested classes without support for short-circuiting
1161+ * in order to ensure all of them are checked for class cycles.
1162+ */
1163+ private static void visitAllNestedClasses (Class <?> clazz , Predicate <Class <?>> predicate ,
1164+ Consumer <Class <?>> consumer ) {
1165+
11611166 if (!isSearchable (clazz )) {
1162- return true ;
1167+ return ;
11631168 }
11641169
11651170 if (isInnerClass (clazz ) && predicate .test (clazz )) {
@@ -1171,10 +1176,7 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
11711176 for (Class <?> nestedClass : clazz .getDeclaredClasses ()) {
11721177 if (predicate .test (nestedClass )) {
11731178 detectInnerClassCycle (nestedClass );
1174- boolean shouldContinue = visitor .accept (nestedClass );
1175- if (!shouldContinue ) {
1176- return false ;
1177- }
1179+ consumer .accept (nestedClass );
11781180 }
11791181 }
11801182 }
@@ -1183,20 +1185,12 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
11831185 }
11841186
11851187 // Search class hierarchy
1186- boolean shouldContinue = visitNestedClasses (clazz .getSuperclass (), predicate , visitor );
1187- if (!shouldContinue ) {
1188- return false ;
1189- }
1188+ visitAllNestedClasses (clazz .getSuperclass (), predicate , consumer );
11901189
11911190 // Search interface hierarchy
11921191 for (Class <?> ifc : clazz .getInterfaces ()) {
1193- shouldContinue = visitNestedClasses (ifc , predicate , visitor );
1194- if (!shouldContinue ) {
1195- return false ;
1196- }
1192+ visitAllNestedClasses (ifc , predicate , consumer );
11971193 }
1198-
1199- return true ;
12001194 }
12011195
12021196 /**
@@ -1936,14 +1930,4 @@ static Throwable getUnderlyingCause(Throwable t) {
19361930 return t ;
19371931 }
19381932
1939- private interface Visitor <T > {
1940-
1941- /**
1942- * @return {@code true} if the visitor should continue searching;
1943- * {@code false} if the visitor should stop
1944- */
1945- boolean accept (T value );
1946-
1947- }
1948-
19491933}
0 commit comments