Skip to content

Commit

Permalink
Fix anyOf/oneOf normalization for 3.1 spec (#19758)
Browse files Browse the repository at this point in the history
* fix anyOf/oneOf normalization for 3.1 spec

* update samples
  • Loading branch information
wing328 authored Oct 3, 2024
1 parent fad33df commit 2111713
Show file tree
Hide file tree
Showing 6 changed files with 68 additions and 9 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -516,7 +516,7 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
return schema;
}

if ((visitedSchemas.contains(schema))) {
if (visitedSchemas.contains(schema)) {
return schema; // skip due to circular reference
} else {
visitedSchemas.add(schema);
Expand All @@ -535,7 +535,6 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
return normalizeAnyOf(schema, visitedSchemas);
} else if (ModelUtils.isAllOfWithProperties(schema)) { // allOf with properties
schema = normalizeAllOfWithProperties(schema, visitedSchemas);
normalizeSchema(schema, visitedSchemas);
} else if (ModelUtils.isAllOf(schema)) { // allOf
return normalizeAllOf(schema, visitedSchemas);
} else if (ModelUtils.isComposedSchema(schema)) { // composed schema
Expand Down Expand Up @@ -643,15 +642,19 @@ private Schema normalizeAllOfWithProperties(Schema schema, Set<Schema> visitedSc
}

private Schema normalizeOneOf(Schema schema, Set<Schema> visitedSchemas) {
for (Object item : schema.getOneOf()) {
for (int i = 0; i < schema.getOneOf().size(); i++) {
// normalize oneOf sub schemas one by one
Object item = schema.getOneOf().get(i);

if (item == null) {
continue;
}
if (!(item instanceof Schema)) {
throw new RuntimeException("Error! oneOf schema is not of the type Schema: " + item);
}
// normalize oenOf sub schemas one by one
normalizeSchema((Schema) item, visitedSchemas);

// update sub-schema with the updated schema
schema.getOneOf().set(i, normalizeSchema((Schema) item, visitedSchemas));
}
// process rules here
schema = processSimplifyOneOf(schema);
Expand All @@ -660,16 +663,20 @@ private Schema normalizeOneOf(Schema schema, Set<Schema> visitedSchemas) {
}

private Schema normalizeAnyOf(Schema schema, Set<Schema> visitedSchemas) {
for (Object item : schema.getAnyOf()) {
for (int i = 0; i < schema.getAnyOf().size(); i++) {
// normalize anyOf sub schemas one by one
Object item = schema.getAnyOf().get(i);

if (item == null) {
continue;
}

if (!(item instanceof Schema)) {
throw new RuntimeException("Error! anyOf schema is not of the type Schema: " + item);
}
// normalize anyOf sub schemas one by one
normalizeSchema((Schema) item, visitedSchemas);

// update sub-schema with the updated schema
schema.getAnyOf().set(i, normalizeSchema((Schema) item, visitedSchemas));
}

// process rules here
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,7 +600,9 @@ public static Schema<?> getSchemaItems(Schema schema) {
Schema<?> items = schema.getItems();
if (items == null) {
if (schema instanceof JsonSchema) { // 3.1 spec
// do nothing as the schema may contain prefixItems only
// set the items to a new schema (any type)
items = new Schema<>();
schema.setItems(items);
} else { // 3.0 spec, default to string
LOGGER.error("Undefined array inner type for `{}`. Default to String.", schema.getName());
items = new StringSchema().description("TODO default missing array inner type to string");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,16 @@ public void testOpenAPINormalizerProcessingArraySchema31Spec() {
assertNotEquals(((Schema) schema7.getProperties().get("with_prefixitems")).getPrefixItems(), null);
assertEquals(((Schema) schema7.getProperties().get("without_items")).getItems(), null);

Schema schema9 = openAPI.getComponents().getSchemas().get("AnyOfArrayWithPrefixItems");
assertEquals(((Schema) schema9.getAnyOf().get(0)).getItems(), null);
assertNotEquals(((Schema) schema9.getAnyOf().get(0)).getPrefixItems(), null);
assertEquals(((Schema) schema9.getAnyOf().get(1)).getItems(), null);

Schema schema11 = openAPI.getComponents().getSchemas().get("OneOfArrayWithPrefixItems");
assertEquals(((Schema) schema11.getOneOf().get(0)).getItems(), null);
assertNotEquals(((Schema) schema11.getOneOf().get(0)).getPrefixItems(), null);
assertEquals(((Schema) schema11.getOneOf().get(1)).getItems(), null);

Map<String, String> inputRules = Map.of("NORMALIZE_31SPEC", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, inputRules);
openAPINormalizer.normalize();
Expand Down Expand Up @@ -632,6 +642,16 @@ public void testOpenAPINormalizerProcessingArraySchema31Spec() {
assertNotEquals(((Schema) schema8.getProperties().get("with_prefixitems")).getItems(), null);
assertEquals(((Schema) schema8.getProperties().get("with_prefixitems")).getPrefixItems(), null);
assertNotEquals(((Schema) schema8.getProperties().get("without_items")).getItems(), null);

Schema schema10 = openAPI.getComponents().getSchemas().get("AnyOfArrayWithPrefixItems");
assertNotEquals(((Schema) schema10.getAnyOf().get(0)).getItems(), null);
assertEquals(((Schema) schema10.getAnyOf().get(0)).getPrefixItems(), null);
assertNotEquals(((Schema) schema10.getAnyOf().get(1)).getItems(), null);

Schema schema12 = openAPI.getComponents().getSchemas().get("OneOfArrayWithPrefixItems");
assertNotEquals(((Schema) schema12.getOneOf().get(0)).getItems(), null);
assertEquals(((Schema) schema12.getOneOf().get(0)).getPrefixItems(), null);
assertNotEquals(((Schema) schema12.getOneOf().get(1)).getItems(), null);
}

@Test
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -461,4 +461,12 @@ public void testCloneDateTimeSchemaWithExample() {
Assert.assertEquals(deepCopy, schema);
Assert.assertNotSame(deepCopy, schema);
}

@Test
public void testGetSchemaItemsWith31Spec() {
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/issue_18291.yaml");
Schema arrayWithPrefixItems = ModelUtils.getSchema(openAPI, "ArrayWithPrefixItems");
Assert.assertNotNull(ModelUtils.getSchemaItems((Schema) arrayWithPrefixItems.getProperties().get("with_prefixitems")));
Assert.assertNotNull(ModelUtils.getSchemaItems((Schema) arrayWithPrefixItems.getProperties().get("without_items")));
}
}
20 changes: 20 additions & 0 deletions modules/openapi-generator/src/test/resources/3_1/issue_18291.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,23 @@ components:
minItems: 2
without_items:
type: array
AnyOfArrayWithPrefixItems:
anyOf:
- type: array
prefixItems:
- type: number
title: Longitude
- type: number
title: Latitude
maxItems: 2
minItems: 2
- type: array
OneOfArrayWithPrefixItems:
oneOf:
- type: array
prefixItems:
- type: integer
- type: integer
maxItems: 3
minItems: 3
- type: array
2 changes: 2 additions & 0 deletions samples/client/petstore/java/okhttp-gson-3.1/api/openapi.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -815,6 +815,7 @@ paths:
items:
$ref: '#/components/schemas/myObject'
nullable: true
type: array
description: ""
tags:
- fake
Expand Down Expand Up @@ -1185,6 +1186,7 @@ components:
- type: string
- items:
type: string
type: array
securitySchemes:
petstore_auth:
flows:
Expand Down

0 comments on commit 2111713

Please sign in to comment.