Skip to content

Commit

Permalink
refs #4771 - schema resolution for container types and oas31
Browse files Browse the repository at this point in the history
  • Loading branch information
frantuma committed Nov 18, 2024
1 parent 24e87c5 commit 94ae2d1
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,11 @@ public ObjectMapper objectMapper() {
@Override
public Schema resolve(AnnotatedType annotatedType, ModelConverterContext context, Iterator<ModelConverter> 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<String> requiredProps = new ArrayList<>();
Expand Down Expand Up @@ -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()));
Expand All @@ -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());
Expand Down Expand Up @@ -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());
Expand Down Expand Up @@ -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<Schema> reResolvedProperty = AnnotationsUtils.getSchemaFromAnnotation(ctxSchema, annotatedType.getComponents(), null, openapi31, property, schemaResolution, context);
if (reResolvedProperty.isPresent()) {
property = reResolvedProperty.get();
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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"),
Expand Down

0 comments on commit 94ae2d1

Please sign in to comment.