Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix anyOf/oneOf normalization for 3.1 spec #19758

Merged
merged 2 commits into from
Oct 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading