diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/AnnotatedType.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/AnnotatedType.java index 537a9d5dde..16000fcfff 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/AnnotatedType.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/AnnotatedType.java @@ -277,9 +277,13 @@ public boolean equals(Object o) { AnnotatedType that = (AnnotatedType) o; List thisAnnotations = getProcessedAnnotations(this.ctxAnnotations); List thatAnnotations = getProcessedAnnotations(that.ctxAnnotations); + String thisParentName = this.parent != null ? this.parent.getName() : null; + String thatParentName = that.parent != null ? that.parent.getName() : null; + return includePropertiesWithoutJSONView == that.includePropertiesWithoutJSONView && schemaProperty == that.schemaProperty && isSubtype == that.isSubtype && + (!schemaProperty || Objects.equals(thisParentName, thatParentName)) && Objects.equals(type, that.type) && Objects.equals(thisAnnotations, thatAnnotations) && Objects.equals(jsonViewAnnotation, that.jsonViewAnnotation) && @@ -289,7 +293,8 @@ public boolean equals(Object o) { @Override public int hashCode() { List processedAnnotations = getProcessedAnnotations(this.ctxAnnotations); - return Objects.hash(type, jsonViewAnnotation, includePropertiesWithoutJSONView, processedAnnotations, schemaProperty, isSubtype, schemaProperty ? propertyName : null); + String parentName = (schemaProperty && this.parent != null) ? this.parent.getName() : null; + return Objects.hash(type, jsonViewAnnotation, includePropertiesWithoutJSONView, processedAnnotations, schemaProperty, isSubtype, schemaProperty ? propertyName : null, parentName); } private boolean processableAnnotationPackage(Package pkg) { diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/RecursivePropertyMissingTest.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/RecursivePropertyMissingTest.java new file mode 100644 index 0000000000..60fa5b80e8 --- /dev/null +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/RecursivePropertyMissingTest.java @@ -0,0 +1,43 @@ +package io.swagger.v3.core.resolving; + +import io.swagger.v3.core.converter.ModelConverters; +import io.swagger.v3.oas.models.media.Schema; +import org.testng.annotations.Test; + +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyDescription; + +import static org.testng.Assert.assertNotNull; +import static org.testng.Assert.assertEquals; + +public class RecursivePropertyMissingTest { + + static class WrapperDTO { + @JsonProperty("nodes") + @JsonPropertyDescription("Child nodes") + public List nodes; + } + + static class TestNodeDTO { + @JsonProperty("name") + public String name; + + @JsonProperty("nodes") + @JsonPropertyDescription("Child nodes") + public List nodes; + } + + @Test + public void testRecursivePropertyNotMissing() { + Map schemas = ModelConverters.getInstance().readAll(WrapperDTO.class); + Schema testNodeDTOSchema = schemas.get("TestNodeDTO"); + assertNotNull(testNodeDTOSchema); + + Map properties = testNodeDTOSchema.getProperties(); + assertNotNull(properties, "Properties should not be null"); + assertNotNull(properties.get("nodes"), "The 'nodes' property is missing from TestNodeDTO schema"); + } +} diff --git a/modules/swagger-core/src/test/resources/converting/ArrayOfSubclassTest_expected30.json b/modules/swagger-core/src/test/resources/converting/ArrayOfSubclassTest_expected30.json index 7cac7074ed..3d4cef01f3 100644 --- a/modules/swagger-core/src/test/resources/converting/ArrayOfSubclassTest_expected30.json +++ b/modules/swagger-core/src/test/resources/converting/ArrayOfSubclassTest_expected30.json @@ -79,6 +79,15 @@ }, "friend" : { "type" : "string" + }, + "baseArray" : { + "minItems" : 0, + "uniqueItems" : true, + "type" : "array", + "description" : "Thingy", + "items" : { + "$ref" : "#/components/schemas/Base" + } } }, "description" : "The SubB class"