43
43
import java .util .Collections ;
44
44
import java .util .Date ;
45
45
import java .util .HashMap ;
46
- import java .util .HashSet ;
46
+ import java .util .LinkedHashMap ;
47
47
import java .util .LinkedHashSet ;
48
48
import java .util .LinkedList ;
49
49
import java .util .List ;
@@ -228,7 +228,7 @@ public List<KubernetesValidationRule> getValidationRules() {
228
228
*/
229
229
protected T internalFrom (TypeDef definition , String ... ignore ) {
230
230
InternalSchemaSwaps schemaSwaps = new InternalSchemaSwaps ();
231
- return internalFromImpl (definition , new HashSet <>(), schemaSwaps , ignore );
231
+ return internalFromImpl (definition , new LinkedHashMap <>(), schemaSwaps , ignore );
232
232
}
233
233
234
234
private static ClassRef extractClassRef (Object type ) {
@@ -294,7 +294,8 @@ private static Stream<KubernetesValidationRule> extractKubernetesValidationRules
294
294
}
295
295
}
296
296
297
- private T internalFromImpl (TypeDef definition , Set <String > visited , InternalSchemaSwaps schemaSwaps , String ... ignore ) {
297
+ private T internalFromImpl (TypeDef definition , LinkedHashMap <String , String > visited , InternalSchemaSwaps schemaSwaps ,
298
+ String ... ignore ) {
298
299
Set <String > ignores = ignore .length > 0 ? new LinkedHashSet <>(Arrays .asList (ignore ))
299
300
: Collections
300
301
.emptySet ();
@@ -327,9 +328,9 @@ private T internalFromImpl(TypeDef definition, Set<String> visited, InternalSche
327
328
328
329
schemaSwaps = schemaSwaps .branchDepths ();
329
330
SwapResult swapResult = schemaSwaps .lookupAndMark (definition .toReference (), name );
331
+ LinkedHashMap <String , String > savedVisited = visited ;
330
332
if (swapResult .onGoing ) {
331
- // hack to prevent cycle detection - this may need improved at some point should stackoverflows be encountered
332
- visited .clear ();
333
+ visited = new LinkedHashMap <>();
333
334
}
334
335
final PropertyFacade facade = new PropertyFacade (property , accessors , swapResult .classRef );
335
336
final Property possiblyRenamedProperty = facade .process ();
@@ -341,6 +342,7 @@ private T internalFromImpl(TypeDef definition, Set<String> visited, InternalSche
341
342
continue ;
342
343
}
343
344
final T schema = internalFromImpl (name , possiblyRenamedProperty .getTypeRef (), visited , schemaSwaps );
345
+ visited = savedVisited ;
344
346
if (facade .preserveUnknownFields ) {
345
347
preserveUnknownFields = true ;
346
348
}
@@ -784,10 +786,11 @@ public abstract T build(B builder,
784
786
* @return the structural schema associated with the specified property
785
787
*/
786
788
public T internalFrom (String name , TypeRef typeRef ) {
787
- return internalFromImpl (name , typeRef , new HashSet <>(), new InternalSchemaSwaps ());
789
+ return internalFromImpl (name , typeRef , new LinkedHashMap <>(), new InternalSchemaSwaps ());
788
790
}
789
791
790
- private T internalFromImpl (String name , TypeRef typeRef , Set <String > visited , InternalSchemaSwaps schemaSwaps ) {
792
+ private T internalFromImpl (String name , TypeRef typeRef , LinkedHashMap <String , String > visited ,
793
+ InternalSchemaSwaps schemaSwaps ) {
791
794
// Note that ordering of the checks here is meaningful: we need to check for complex types last
792
795
// in case some "complex" types are handled specifically
793
796
if (typeRef .getDimensions () > 0 || io .sundr .model .utils .Collections .isCollection (typeRef )) { // Handle Collections & Arrays
@@ -848,24 +851,17 @@ private T internalFromImpl(String name, TypeRef typeRef, Set<String> visited, In
848
851
}
849
852
}
850
853
851
- // Flag to detect cycles
852
- private boolean resolving = false ;
853
-
854
- private T resolveNestedClass (String name , TypeDef def , Set <String > visited , InternalSchemaSwaps schemaSwaps ) {
855
- if (!resolving ) {
856
- visited .clear ();
857
- resolving = true ;
858
- } else {
859
- String visitedName = name + ":" + def .getFullyQualifiedName ();
860
- if (!def .getFullyQualifiedName ().startsWith ("java" ) && visited .contains (visitedName )) {
861
- throw new IllegalArgumentException (
862
- "Found a cyclic reference involving the field " + name + " of type " + def .getFullyQualifiedName ());
863
- }
864
- visited .add (visitedName );
854
+ private T resolveNestedClass (String name , TypeDef def , LinkedHashMap <String , String > visited ,
855
+ InternalSchemaSwaps schemaSwaps ) {
856
+ if (visited .put (def .getFullyQualifiedName (), name ) != null ) {
857
+ throw new IllegalArgumentException (
858
+ "Found a cyclic reference involving the field of type " + def .getFullyQualifiedName () + " starting a field "
859
+ + visited .entrySet ().stream ().map (e -> e .getValue () + " >>\n " + e .getKey ()).collect (Collectors .joining ("." )) + "."
860
+ + name );
865
861
}
866
862
867
863
T res = internalFromImpl (def , visited , schemaSwaps );
868
- resolving = false ;
864
+ visited . remove ( def . getFullyQualifiedName ()) ;
869
865
return res ;
870
866
}
871
867
0 commit comments