diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java index 36ab4d38f0..c66e53c4c6 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/jackson/ModelResolver.java @@ -750,7 +750,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context if (reResolvedProperty.isPresent()) { property = reResolvedProperty.get(); } - reResolvedProperty = AnnotationsUtils.getArraySchema(ctxArraySchema, annotatedType.getComponents(), null, openapi31, property); + reResolvedProperty = AnnotationsUtils.getArraySchema(ctxArraySchema, annotatedType.getComponents(), null, openapi31, property, true); if (reResolvedProperty.isPresent()) { property = reResolvedProperty.get(); } @@ -2701,6 +2701,19 @@ protected void resolveSchemaMembers(Schema schema, AnnotatedType annotatedType, Annotated a = beanDesc.getClassInfo(); Annotation[] annotations = annotatedType.getCtxAnnotations(); resolveSchemaMembers(schema, a, annotations, schemaAnnotation); + if (schemaAnnotation != null) { + if (schemaAnnotation.additionalProperties().equals(io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.TRUE)) { + schema.additionalProperties(true); + } else if (schemaAnnotation.additionalProperties().equals(io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.FALSE)) { + schema.additionalProperties(false); + } else { + if (!schemaAnnotation.additionalPropertiesSchema().equals(Void.class)) { + Schema additionalPropertiesSchema = resolve(new AnnotatedType(schemaAnnotation.additionalPropertiesSchema()), context, next); + additionalPropertiesSchema = buildRefSchemaIfObject(additionalPropertiesSchema, context); + schema.additionalProperties(additionalPropertiesSchema); + } + } + } if (openapi31 && schema != null && schemaAnnotation != null) { if (!Void.class.equals(schemaAnnotation.contentSchema())) { @@ -2734,18 +2747,6 @@ protected void resolveSchemaMembers(Schema schema, AnnotatedType annotatedType, schema.setUnevaluatedProperties(unevaluatedProperties); } - if (schemaAnnotation.additionalProperties().equals(io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.TRUE)) { - schema.additionalProperties(true); - } else if (schemaAnnotation.additionalProperties().equals(io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.FALSE)) { - schema.additionalProperties(false); - } else { - if (!schemaAnnotation.additionalPropertiesSchema().equals(Void.class)) { - Schema additionalPropertiesSchema = resolve(new AnnotatedType(schemaAnnotation.additionalPropertiesSchema()), context, next); - additionalPropertiesSchema = buildRefSchemaIfObject(additionalPropertiesSchema, context); - schema.additionalProperties(additionalPropertiesSchema); - } - } - final Map> dependentRequired = resolveDependentRequired(a, annotations, schemaAnnotation); if (dependentRequired != null && !dependentRequired.isEmpty()) { schema.setDependentRequired(dependentRequired); diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java index cb26009e0a..7dbc5ab396 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/util/AnnotationsUtils.java @@ -126,9 +126,8 @@ public static boolean hasSchemaAnnotation(io.swagger.v3.oas.annotations.media.Sc && schema.patternProperties().length == 0 && schema.properties().length == 0 && StringUtils.isBlank(schema._const()) - - && schema.additionalProperties().equals(io.swagger.v3.oas.annotations.media.Schema.AdditionalPropertiesValue.USE_ADDITIONAL_PROPERTIES_ANNOTATION) + && schema.additionalPropertiesSchema().equals(Void.class) ) { return false; } diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java index 7949b1a010..afc7cfa1b1 100644 --- a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/ReaderTest.java @@ -15,10 +15,12 @@ import io.swagger.v3.jaxrs2.matchers.SerializationMatchers; import io.swagger.v3.jaxrs2.petstore31.PetResource; import io.swagger.v3.jaxrs2.petstore31.TagResource; +import io.swagger.v3.jaxrs2.resources.ArraySchemaImplementationResource; import io.swagger.v3.jaxrs2.resources.DefaultResponseResource; import io.swagger.v3.jaxrs2.resources.Misc31Resource; import io.swagger.v3.jaxrs2.resources.ParameterMaximumValueResource; import io.swagger.v3.jaxrs2.resources.ResponseReturnTypeResource; +import io.swagger.v3.jaxrs2.resources.SchemaAdditionalPropertiesBooleanResource; import io.swagger.v3.jaxrs2.resources.SchemaAdditionalPropertiesResource; import io.swagger.v3.jaxrs2.resources.SchemaPropertiesResource; import io.swagger.v3.jaxrs2.resources.SiblingPropResource; @@ -3081,6 +3083,81 @@ public void testSchemaAdditionalProperties() { SerializationMatchers.assertEqualsToYaml(openAPI, yaml); } + @Test(description = "Test Schema AdditionalProperties annotations") + public void testSchemaAdditionalPropertiesBoolean() { + ModelConverters.reset(); + SwaggerConfiguration config = new SwaggerConfiguration().openAPI(new OpenAPI()).schemaResolution(Schema.SchemaResolution.ALL_OF); + Reader reader = new Reader(config); + + OpenAPI openAPI = reader.read(SchemaAdditionalPropertiesBooleanResource.class); + String yaml = "openapi: 3.0.1\n" + + "paths:\n" + + " /test:\n" + + " get:\n" + + " operationId: test\n" + + " responses:\n" + + " default:\n" + + " description: default response\n" + + " content:\n" + + " '*/*':\n" + + " schema:\n" + + " $ref: '#/components/schemas/Pet'\n" + + "components:\n" + + " schemas:\n" + + " Bar:\n" + + " type: object\n" + + " properties:\n" + + " foo:\n" + + " type: string\n" + + " Pet:\n" + + " type: object\n" + + " properties:\n" + + " bar:\n" + + " allOf:\n" + + " - additionalProperties:\n" + + " $ref: '#/components/schemas/Bar'\n" + + " - $ref: '#/components/schemas/Bar'\n" + + " vbar:\n" + + " allOf:\n" + + " - additionalProperties: false\n" + + " - $ref: '#/components/schemas/Bar'\n" + + " additionalProperties: false\n"; + SerializationMatchers.assertEqualsToYaml(openAPI, yaml); + ModelConverters.reset(); + } + + @Test(description = "Test ArraySchema implementation annotations") + public void testArraySchemaImplementation() { + SwaggerConfiguration config = new SwaggerConfiguration().openAPI31(true).openAPI(new OpenAPI()); + Reader reader = new Reader(config); + + OpenAPI openAPI = reader.read(ArraySchemaImplementationResource.class); + String yaml = "openapi: 3.1.0\n" + + "paths:\n" + + " /test:\n" + + " get:\n" + + " operationId: test\n" + + " responses:\n" + + " default:\n" + + " description: default response\n" + + " content:\n" + + " '*/*':\n" + + " schema:\n" + + " $ref: '#/components/schemas/Pet'\n" + + "components:\n" + + " schemas:\n" + + " Pet:\n" + + " type: object\n" + + " properties:\n" + + " cars:\n" + + " type: array\n" + + " items:\n" + + " type: integer\n" + + " format: int32\n" + + " description: A house in a street\n"; + SerializationMatchers.assertEqualsToYaml31(openAPI, yaml); + } + @Test(description = "Responses schema resolved from return type") public void testResponseReturnType() { Reader reader = new Reader(new OpenAPI()); diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/ArraySchemaImplementationResource.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/ArraySchemaImplementationResource.java new file mode 100644 index 0000000000..45435e2878 --- /dev/null +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/ArraySchemaImplementationResource.java @@ -0,0 +1,23 @@ +package io.swagger.v3.jaxrs2.resources; + +import io.swagger.v3.oas.annotations.media.ArraySchema; +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import java.util.List; + +public class ArraySchemaImplementationResource { + + static class Pet { + @ArraySchema(schema = @Schema(implementation = Integer.class, description = "A house in a street")) + public List cars; + } + + @GET + @Path("/test") + public Pet test() { + return null; + } + +} diff --git a/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/SchemaAdditionalPropertiesBooleanResource.java b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/SchemaAdditionalPropertiesBooleanResource.java new file mode 100644 index 0000000000..286672db06 --- /dev/null +++ b/modules/swagger-jaxrs2/src/test/java/io/swagger/v3/jaxrs2/resources/SchemaAdditionalPropertiesBooleanResource.java @@ -0,0 +1,36 @@ +package io.swagger.v3.jaxrs2.resources; + +import io.swagger.v3.oas.annotations.media.Schema; + +import javax.ws.rs.GET; +import javax.ws.rs.Path; + + +public class SchemaAdditionalPropertiesBooleanResource { + + @Schema(additionalProperties = Schema.AdditionalPropertiesValue.FALSE) + static class Pet { + @Schema(additionalPropertiesSchema = Bar.class) + public Bar bar; + + @Schema(additionalProperties = Schema.AdditionalPropertiesValue.FALSE) + public Bar vbar; + } + + + static class Bar { + public String foo; + } + + @Schema(description = "A car") + static class Car { + public String foo; + } + + @GET + @Path("/test") + public Pet test() { + return null; + } + +}