4343import java .util .Collections ;
4444import java .util .Date ;
4545import java .util .HashMap ;
46- import java .util .HashSet ;
46+ import java .util .LinkedHashMap ;
4747import java .util .LinkedHashSet ;
4848import java .util .LinkedList ;
4949import java .util .List ;
@@ -228,7 +228,7 @@ public List<KubernetesValidationRule> getValidationRules() {
228228 */
229229 protected T internalFrom (TypeDef definition , String ... ignore ) {
230230 InternalSchemaSwaps schemaSwaps = new InternalSchemaSwaps ();
231- return internalFromImpl (definition , new HashSet <>(), schemaSwaps , ignore );
231+ return internalFromImpl (definition , new LinkedHashMap <>(), schemaSwaps , ignore );
232232 }
233233
234234 private static ClassRef extractClassRef (Object type ) {
@@ -294,7 +294,8 @@ private static Stream<KubernetesValidationRule> extractKubernetesValidationRules
294294 }
295295 }
296296
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 ) {
298299 Set <String > ignores = ignore .length > 0 ? new LinkedHashSet <>(Arrays .asList (ignore ))
299300 : Collections
300301 .emptySet ();
@@ -327,9 +328,9 @@ private T internalFromImpl(TypeDef definition, Set<String> visited, InternalSche
327328
328329 schemaSwaps = schemaSwaps .branchDepths ();
329330 SwapResult swapResult = schemaSwaps .lookupAndMark (definition .toReference (), name );
331+ LinkedHashMap <String , String > savedVisited = visited ;
330332 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 <>();
333334 }
334335 final PropertyFacade facade = new PropertyFacade (property , accessors , swapResult .classRef );
335336 final Property possiblyRenamedProperty = facade .process ();
@@ -341,6 +342,7 @@ private T internalFromImpl(TypeDef definition, Set<String> visited, InternalSche
341342 continue ;
342343 }
343344 final T schema = internalFromImpl (name , possiblyRenamedProperty .getTypeRef (), visited , schemaSwaps );
345+ visited = savedVisited ;
344346 if (facade .preserveUnknownFields ) {
345347 preserveUnknownFields = true ;
346348 }
@@ -784,10 +786,11 @@ public abstract T build(B builder,
784786 * @return the structural schema associated with the specified property
785787 */
786788 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 ());
788790 }
789791
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 ) {
791794 // Note that ordering of the checks here is meaningful: we need to check for complex types last
792795 // in case some "complex" types are handled specifically
793796 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
848851 }
849852 }
850853
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 );
865861 }
866862
867863 T res = internalFromImpl (def , visited , schemaSwaps );
868- resolving = false ;
864+ visited . remove ( def . getFullyQualifiedName ()) ;
869865 return res ;
870866 }
871867
0 commit comments