Skip to content

Commit bb3d0c0

Browse files
authored
task: improve the cycle error message
Signed-off-by: Steve Hawkins <[email protected]>
1 parent 64db0b0 commit bb3d0c0

File tree

1 file changed

+18
-22
lines changed

1 file changed

+18
-22
lines changed

Diff for: crd-generator/api/src/main/java/io/fabric8/crd/generator/AbstractJsonSchema.java

+18-22
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
import java.util.Collections;
4444
import java.util.Date;
4545
import java.util.HashMap;
46-
import java.util.HashSet;
46+
import java.util.LinkedHashMap;
4747
import java.util.LinkedHashSet;
4848
import java.util.LinkedList;
4949
import 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

Comments
 (0)