49
49
import java .util .Optional ;
50
50
import java .util .Set ;
51
51
import java .util .concurrent .ConcurrentHashMap ;
52
+ import java .util .concurrent .atomic .AtomicBoolean ;
53
+ import java .util .function .Consumer ;
52
54
import java .util .function .Predicate ;
53
55
import java .util .regex .Matcher ;
54
56
import java .util .regex .Pattern ;
@@ -1119,10 +1121,7 @@ public static List<Class<?>> findNestedClasses(Class<?> clazz, Predicate<Class<?
1119
1121
Preconditions .notNull (predicate , "Predicate must not be null" );
1120
1122
1121
1123
Set <Class <?>> candidates = new LinkedHashSet <>();
1122
- visitNestedClasses (clazz , predicate , nestedClass -> {
1123
- candidates .add (nestedClass );
1124
- return true ;
1125
- });
1124
+ visitAllNestedClasses (clazz , predicate , candidates ::add );
1126
1125
return List .copyOf (candidates );
1127
1126
}
1128
1127
@@ -1144,8 +1143,9 @@ public static boolean isNestedClassPresent(Class<?> clazz, Predicate<Class<?>> p
1144
1143
Preconditions .notNull (clazz , "Class must not be null" );
1145
1144
Preconditions .notNull (predicate , "Predicate must not be null" );
1146
1145
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 ();
1149
1149
}
1150
1150
1151
1151
/**
@@ -1156,10 +1156,15 @@ public static Stream<Class<?>> streamNestedClasses(Class<?> clazz, Predicate<Cla
1156
1156
return findNestedClasses (clazz , predicate ).stream ();
1157
1157
}
1158
1158
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
+
1161
1166
if (!isSearchable (clazz )) {
1162
- return true ;
1167
+ return ;
1163
1168
}
1164
1169
1165
1170
if (isInnerClass (clazz ) && predicate .test (clazz )) {
@@ -1171,10 +1176,7 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
1171
1176
for (Class <?> nestedClass : clazz .getDeclaredClasses ()) {
1172
1177
if (predicate .test (nestedClass )) {
1173
1178
detectInnerClassCycle (nestedClass );
1174
- boolean shouldContinue = visitor .accept (nestedClass );
1175
- if (!shouldContinue ) {
1176
- return false ;
1177
- }
1179
+ consumer .accept (nestedClass );
1178
1180
}
1179
1181
}
1180
1182
}
@@ -1183,20 +1185,12 @@ private static boolean visitNestedClasses(Class<?> clazz, Predicate<Class<?>> pr
1183
1185
}
1184
1186
1185
1187
// Search class hierarchy
1186
- boolean shouldContinue = visitNestedClasses (clazz .getSuperclass (), predicate , visitor );
1187
- if (!shouldContinue ) {
1188
- return false ;
1189
- }
1188
+ visitAllNestedClasses (clazz .getSuperclass (), predicate , consumer );
1190
1189
1191
1190
// Search interface hierarchy
1192
1191
for (Class <?> ifc : clazz .getInterfaces ()) {
1193
- shouldContinue = visitNestedClasses (ifc , predicate , visitor );
1194
- if (!shouldContinue ) {
1195
- return false ;
1196
- }
1192
+ visitAllNestedClasses (ifc , predicate , consumer );
1197
1193
}
1198
-
1199
- return true ;
1200
1194
}
1201
1195
1202
1196
/**
@@ -1936,14 +1930,4 @@ static Throwable getUnderlyingCause(Throwable t) {
1936
1930
return t ;
1937
1931
}
1938
1932
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
-
1949
1933
}
0 commit comments