diff --git a/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java b/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java index 7149e587c5..843455e7d3 100644 --- a/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java +++ b/modules/swagger-core/src/main/java/io/swagger/v3/core/converter/ModelConverters.java @@ -81,7 +81,8 @@ public static ModelConverters getInstance(boolean openapi31, Schema.SchemaResolu synchronized (ModelConverters.class) { if (openapi31) { if (SINGLETON31 == null) { - SINGLETON31 = new ModelConverters(openapi31, Schema.SchemaResolution.DEFAULT); + boolean applySchemaResolution = Boolean.parseBoolean(System.getProperty(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY, "false")) || Boolean.parseBoolean(System.getenv(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY)); + SINGLETON31 = new ModelConverters(openapi31, applySchemaResolution ? schemaResolution : Schema.SchemaResolution.DEFAULT); init(SINGLETON31); } return SINGLETON31; 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 b95ad74446..f266f6a6e0 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 @@ -141,6 +141,11 @@ public ObjectMapper objectMapper() { @Override public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context, Iterator next) { + + boolean applySchemaResolution = + !openapi31 || + (Boolean.parseBoolean(System.getProperty(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY, "false")) || + Boolean.parseBoolean(System.getenv(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY))); boolean isPrimitive = false; Schema model = null; List requiredProps = new ArrayList<>(); @@ -449,7 +454,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context ).collect(Collectors.toList())); } - + Schema.SchemaResolution containerResolvedSchemaResolution = AnnotationsUtils.resolveSchemaResolution(this.schemaResolution, resolvedSchemaAnnotation); if (keyType != null && valueType != null) { if (ReflectionUtils.isSystemTypeNotArray(type) && !annotatedType.isSchemaProperty() && !annotatedType.isResolveAsRef()) { context.resolve(new AnnotatedType().components(annotatedType.getComponents()).type(valueType).jsonViewAnnotation(annotatedType.getJsonViewAnnotation())); @@ -471,9 +476,13 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context pName = addPropertiesSchema.getName(); } if (isObjectSchema(addPropertiesSchema) && pName != null) { - // create a reference for the items if (context.getDefinedModels().containsKey(pName)) { - addPropertiesSchema = new Schema().$ref(constructRef(pName)); + if (Schema.SchemaResolution.INLINE.equals(containerResolvedSchemaResolution) && applySchemaResolution) { + addPropertiesSchema = context.getDefinedModels().get(pName); + } else { + // create a reference for the items + addPropertiesSchema = new Schema().$ref(constructRef(pName)); + } } } else if (addPropertiesSchema.get$ref() != null) { addPropertiesSchema = new Schema().$ref(StringUtils.isNotEmpty(addPropertiesSchema.get$ref()) ? addPropertiesSchema.get$ref() : addPropertiesSchema.getName()); @@ -519,9 +528,13 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context pName = items.getName(); } if (isObjectSchema(items) && pName != null) { - // create a reference for the items if (context.getDefinedModels().containsKey(pName)) { - items = new Schema().$ref(constructRef(pName)); + if (Schema.SchemaResolution.INLINE.equals(containerResolvedSchemaResolution) && applySchemaResolution) { + items = context.getDefinedModels().get(pName); + } else { + // create a reference for the items + items = new Schema().$ref(constructRef(pName)); + } } } else if (items.get$ref() != null) { items = new Schema().$ref(StringUtils.isNotEmpty(items.get$ref()) ? items.get$ref() : items.getName()); @@ -738,7 +751,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context property = context.resolve(aType); property = clone(property); Schema ctxProperty = null; - if (openapi31) { + if (!applySchemaResolution) { Optional reResolvedProperty = AnnotationsUtils.getSchemaFromAnnotation(ctxSchema, annotatedType.getComponents(), null, openapi31, property, schemaResolution, context); if (reResolvedProperty.isPresent()) { property = reResolvedProperty.get(); @@ -822,7 +835,7 @@ public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context } } } else if (property.get$ref() != null) { - if (!openapi31) { + if (applySchemaResolution) { if (Schema.SchemaResolution.ALL_OF.equals(resolvedSchemaResolution) && ctxProperty != null) { property = new Schema() .addAllOfItem(ctxProperty) diff --git a/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4771Test.java b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4771Test.java new file mode 100644 index 0000000000..d246a584d0 --- /dev/null +++ b/modules/swagger-core/src/test/java/io/swagger/v3/core/resolving/Ticket4771Test.java @@ -0,0 +1,98 @@ +package io.swagger.v3.core.resolving; + +import io.swagger.v3.core.converter.AnnotatedType; +import io.swagger.v3.core.converter.ModelConverters; +import io.swagger.v3.core.converter.ResolvedSchema; +import io.swagger.v3.core.matchers.SerializationMatchers; +import io.swagger.v3.oas.models.media.Schema; +import org.testng.annotations.Test; + +public class Ticket4771Test { + + @Test + public void testArraySchemaItemsValidation(){ + ModelConverters.reset(); + System.clearProperty(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY); + ResolvedSchema schema = ModelConverters.getInstance(false, Schema.SchemaResolution.INLINE).resolveAsResolvedSchema(new AnnotatedType().type(CustomClass[].class)); + String expectedJson = "{\n" + + " \"schema\" : {\n" + + " \"type\" : \"array\",\n" + + " \"items\" : {\n" + + " \"type\" : \"object\",\n" + + " \"properties\" : {\n" + + " \"foo\" : {\n" + + " \"type\" : \"string\"\n" + + " }\n" + + " }\n" + + " }\n" + + " },\n" + + " \"referencedSchemas\" : {\n" + + " \"CustomClass\" : {\n" + + " \"type\" : \"object\",\n" + + " \"properties\" : {\n" + + " \"foo\" : {\n" + + " \"type\" : \"string\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + SerializationMatchers.assertEqualsToJson(schema, expectedJson); + ModelConverters.reset(); + schema = ModelConverters.getInstance(true, Schema.SchemaResolution.INLINE).resolveAsResolvedSchema(new AnnotatedType().type(CustomClass[].class)); + expectedJson = "{\n" + + " \"schema\" : {\n" + + " \"type\" : \"array\",\n" + + " \"items\" : {\n" + + " \"$ref\" : \"#/components/schemas/CustomClass\"\n" + + " }\n" + + " },\n" + + " \"referencedSchemas\" : {\n" + + " \"CustomClass\" : {\n" + + " \"type\" : \"object\",\n" + + " \"properties\" : {\n" + + " \"foo\" : {\n" + + " \"type\" : \"string\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + SerializationMatchers.assertEqualsToJson31(schema, expectedJson); + ModelConverters.reset(); + System.setProperty(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY, "true"); + schema = ModelConverters.getInstance(true, Schema.SchemaResolution.INLINE).resolveAsResolvedSchema(new AnnotatedType().type(CustomClass[].class)); + expectedJson = "{\n" + + " \"schema\" : {\n" + + " \"type\" : \"array\",\n" + + " \"items\" : {\n" + + " \"type\" : \"object\",\n" + + " \"properties\" : {\n" + + " \"foo\" : {\n" + + " \"type\" : \"string\"\n" + + " }\n" + + " }\n" + + " }\n" + + " },\n" + + " \"referencedSchemas\" : {\n" + + " \"CustomClass\" : {\n" + + " \"type\" : \"object\",\n" + + " \"properties\" : {\n" + + " \"foo\" : {\n" + + " \"type\" : \"string\"\n" + + " }\n" + + " }\n" + + " }\n" + + " }\n" + + "}"; + SerializationMatchers.assertEqualsToJson31(schema, expectedJson); + System.clearProperty(Schema.APPLY_SCHEMA_RESOLUTION_PROPERTY); + ModelConverters.reset(); + + + } + + private static class CustomClass { + public String foo; + } +} diff --git a/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/media/Schema.java b/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/media/Schema.java index d17c2a4f62..dbea8e491a 100644 --- a/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/media/Schema.java +++ b/modules/swagger-models/src/main/java/io/swagger/v3/oas/models/media/Schema.java @@ -46,6 +46,7 @@ public String toString() { } public static final String SCHEMA_RESOLUTION_PROPERTY = "schema-resolution"; + public static final String APPLY_SCHEMA_RESOLUTION_PROPERTY = "apply-schema-resolution"; public enum SchemaResolution { @JsonProperty("default") DEFAULT("default"),