52
52
import java .util .Optional ;
53
53
import java .util .Set ;
54
54
import java .util .concurrent .ConcurrentHashMap ;
55
+ import java .util .concurrent .atomic .AtomicBoolean ;
56
+ import java .util .function .Consumer ;
55
57
import java .util .function .Predicate ;
56
58
import java .util .regex .Matcher ;
57
59
import java .util .regex .Pattern ;
@@ -1236,10 +1238,7 @@ public static List<Class<?>> findNestedClasses(Class<?> clazz, Predicate<Class<?
1236
1238
Preconditions .notNull (predicate , "Predicate must not be null" );
1237
1239
1238
1240
Set <Class <?>> candidates = new LinkedHashSet <>();
1239
- visitNestedClasses (clazz , predicate , nestedClass -> {
1240
- candidates .add (nestedClass );
1241
- return true ;
1242
- });
1241
+ visitAllNestedClasses (clazz , predicate , candidates ::add );
1243
1242
return Collections .unmodifiableList (new ArrayList <>(candidates ));
1244
1243
}
1245
1244
@@ -1261,8 +1260,9 @@ public static boolean isNestedClassPresent(Class<?> clazz, Predicate<Class<?>> p
1261
1260
Preconditions .notNull (clazz , "Class must not be null" );
1262
1261
Preconditions .notNull (predicate , "Predicate must not be null" );
1263
1262
1264
- boolean visitorWasNotCalled = visitNestedClasses (clazz , predicate , __ -> false );
1265
- return !visitorWasNotCalled ;
1263
+ AtomicBoolean foundNestedClass = new AtomicBoolean (false );
1264
+ visitAllNestedClasses (clazz , predicate , __ -> foundNestedClass .setPlain (true ));
1265
+ return foundNestedClass .getPlain ();
1266
1266
}
1267
1267
1268
1268
/**
@@ -1273,10 +1273,15 @@ public static Stream<Class<?>> streamNestedClasses(Class<?> clazz, Predicate<Cla
1273
1273
return findNestedClasses (clazz , predicate ).stream ();
1274
1274
}
1275
1275
1276
- private static boolean visitNestedClasses (Class <?> clazz , Predicate <Class <?>> predicate ,
1277
- Visitor <Class <?>> visitor ) {
1276
+ /**
1277
+ * Visit <em>all</em> nested classes without support for short-circuiting
1278
+ * in order to ensure all of them are checked for class cycles.
1279
+ */
1280
+ private static void visitAllNestedClasses (Class <?> clazz , Predicate <Class <?>> predicate ,
1281
+ Consumer <Class <?>> consumer ) {
1282
+
1278
1283
if (!isSearchable (clazz )) {
1279
- return true ;
1284
+ return ;
1280
1285
}
1281
1286
1282
1287
if (isInnerClass (clazz ) && predicate .test (clazz )) {
@@ -1288,10 +1293,7 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
1288
1293
for (Class <?> nestedClass : clazz .getDeclaredClasses ()) {
1289
1294
if (predicate .test (nestedClass )) {
1290
1295
detectInnerClassCycle (nestedClass );
1291
- boolean shouldContinue = visitor .accept (nestedClass );
1292
- if (!shouldContinue ) {
1293
- return false ;
1294
- }
1296
+ consumer .accept (nestedClass );
1295
1297
}
1296
1298
}
1297
1299
}
@@ -1300,20 +1302,12 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
1300
1302
}
1301
1303
1302
1304
// Search class hierarchy
1303
- boolean shouldContinue = visitNestedClasses (clazz .getSuperclass (), predicate , visitor );
1304
- if (!shouldContinue ) {
1305
- return false ;
1306
- }
1305
+ visitAllNestedClasses (clazz .getSuperclass (), predicate , consumer );
1307
1306
1308
1307
// Search interface hierarchy
1309
1308
for (Class <?> ifc : clazz .getInterfaces ()) {
1310
- shouldContinue = visitNestedClasses (ifc , predicate , visitor );
1311
- if (!shouldContinue ) {
1312
- return false ;
1313
- }
1309
+ visitAllNestedClasses (ifc , predicate , consumer );
1314
1310
}
1315
-
1316
- return true ;
1317
1311
}
1318
1312
1319
1313
/**
@@ -2119,14 +2113,4 @@ private static boolean getLegacySearchSemanticsFlag() {
2119
2113
return isTrue ;
2120
2114
}
2121
2115
2122
- private interface Visitor <T > {
2123
-
2124
- /**
2125
- * @return {@code true} if the visitor should continue searching;
2126
- * {@code false} if the visitor should stop
2127
- */
2128
- boolean accept (T value );
2129
-
2130
- }
2131
-
2132
2116
}
0 commit comments