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 null check in 3.1 spec #18353

Merged
merged 2 commits into from
Apr 11, 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 @@ -890,7 +890,7 @@ public boolean isNullTypeSchema(Schema schema) {

if (schema.getTypes() != null && !schema.getTypes().isEmpty()) {
// 3.1 spec
if (schema.getTypes().size() ==1) { // 1 type only
if (schema.getTypes().size() == 1) { // 1 type only
String type = (String) schema.getTypes().iterator().next();
return type == null || "null".equals(type);
} else { // more than 1 type so must not be just null
Expand All @@ -902,6 +902,11 @@ public boolean isNullTypeSchema(Schema schema) {
if (Boolean.TRUE.equals(schema.getNullable())) {
return true;
}

// for `type: null`
if (schema.getTypes() == null && schema.get$ref() == null) {
return true;
}
} else { // 3.0.x or 2.x spec
if ((schema.getType() == null || schema.getType().equals("null")) && schema.get$ref() == null) {
return true;
Expand Down Expand Up @@ -938,7 +943,7 @@ private Schema processSimplifyOneOf(Schema schema) {
if (oneOfSchemas.size() == 6) {
TreeSet<String> ts = new TreeSet<>();
for (Schema s: oneOfSchemas) {
ts.add(s.getType());
ts.add(ModelUtils.getType(s));
}

if (ts.equals(anyTypeTreeSet)) {
Expand Down Expand Up @@ -1063,7 +1068,7 @@ private Schema processSimplifyAnyOf(Schema schema) {
if (anyOfSchemas.size() == 6) {
TreeSet<String> ts = new TreeSet<>();
for (Schema s: anyOfSchemas) {
ts.add(s.getType());
ts.add(ModelUtils.getType(s));
}

if (ts.equals(anyTypeTreeSet)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2126,6 +2126,25 @@ public static boolean hasAnyOf(Schema schema) {
return false;
}

/**
* Returns schema type.
* For 3.1 spec, return the first one.
*
* @param schema the schema
* @return schema type
*/
public static String getType(Schema schema) {
if (schema == null) {
return null;
}

if (schema instanceof JsonSchema) {
return String.valueOf(schema.getTypes().iterator().next());
} else {
return schema.getType();
}
}

/**
* Returns true if any of the common attributes of the schema (e.g. readOnly, default, maximum, etc) is defined.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf() {
assertEquals(schema2.getOneOf().size(), 4);
assertNull(schema2.getNullable());

Schema schema2b = openAPI.getComponents().getSchemas().get("OneOfTest2");
assertEquals(schema2b.getOneOf().size(), 2);
assertNull(schema2b.getNullable());

Schema schema5 = openAPI.getComponents().getSchemas().get("OneOfNullableTest");
assertEquals(schema5.getOneOf().size(), 3);
assertNull(schema5.getNullable());
Expand Down Expand Up @@ -189,6 +193,11 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf() {
assertTrue(schema4 instanceof IntegerSchema);
assertTrue(schema4.getNullable());

Schema schema4b = openAPI.getComponents().getSchemas().get("OneOfTest2");
assertNull(schema4b.getOneOf());
assertTrue(schema4b instanceof StringSchema);
assertTrue(schema4b.getNullable());

Schema schema6 = openAPI.getComponents().getSchemas().get("OneOfNullableTest");
assertEquals(schema6.getOneOf().size(), 2);
assertTrue(schema6.getNullable());
Expand Down Expand Up @@ -532,7 +541,7 @@ public void testSetContainerToNullable() {
@Test
public void testSetPrimitiveTypesToNullable() {
// test `string|integer|number|boolean`
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0//setPrimitiveTypesToNullable_test.yaml");
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/setPrimitiveTypesToNullable_test.yaml");

Schema schema = openAPI.getComponents().getSchemas().get("Person");
assertEquals(((Schema) schema.getProperties().get("lastName")).getNullable(), null);
Expand All @@ -552,7 +561,7 @@ public void testSetPrimitiveTypesToNullable() {
assertEquals(((Schema) schema2.getProperties().get("first_boolean")).getNullable(), true);

// test `number` only
OpenAPI openAPI2 = TestUtils.parseSpec("src/test/resources/3_0//setPrimitiveTypesToNullable_test.yaml");
OpenAPI openAPI2 = TestUtils.parseSpec("src/test/resources/3_0/setPrimitiveTypesToNullable_test.yaml");

Schema schema3 = openAPI2.getComponents().getSchemas().get("Person");
assertEquals(((Schema) schema3.getProperties().get("lastName")).getNullable(), null);
Expand All @@ -572,7 +581,7 @@ public void testSetPrimitiveTypesToNullable() {
}

@Test
public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
public void testOpenAPINormalizerSimplifyOneOfAnyOf31SpecForIssue18184 () {
// to test the rule SIMPLIFY_ONEOF_ANYOF in 3.1 spec
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/issue_18184.yaml");
// test spec contains anyOf with a ref to enum and another scheme type is null
Expand Down Expand Up @@ -636,6 +645,77 @@ public void testOpenAPINormalizerProcessingArraySchema31Spec() {
assertEquals(((Schema) schema6.getProperties().get("arrayOfStrings")).getItems().getTypes().contains("string"), true);
assertEquals(((Schema) schema6.getProperties().get("arrayOfStrings")).getItems().getType(), "string");
assertEquals(((Schema) schema6.getProperties().get("arrayOfStrings")).getType(), "array");
}

@Test
public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
// to test the rule SIMPLIFY_ONEOF_ANYOF with 3.1 spec
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/simplifyOneOfAnyOf_test.yaml");

Schema schema = openAPI.getComponents().getSchemas().get("AnyOfTest");
assertEquals(schema.getAnyOf().size(), 4);
assertNull(schema.getNullable());

Schema schema2 = openAPI.getComponents().getSchemas().get("OneOfTest");
assertEquals(schema2.getOneOf().size(), 4);
assertNull(schema2.getNullable());

Schema schema2b = openAPI.getComponents().getSchemas().get("OneOfTest2");
assertEquals(schema2b.getOneOf().size(), 2);
assertNull(schema2b.getNullable());

Schema schema5 = openAPI.getComponents().getSchemas().get("OneOfNullableTest");
assertEquals(schema5.getOneOf().size(), 3);
assertNull(schema5.getNullable());

Schema schema7 = openAPI.getComponents().getSchemas().get("Parent");
assertEquals(((Schema) schema7.getProperties().get("number")).getAnyOf().size(), 1);

Schema schema9 = openAPI.getComponents().getSchemas().get("AnyOfStringArrayOfString");
assertEquals(schema9.getAnyOf().size(), 2);

Schema schema11 = openAPI.getComponents().getSchemas().get("AnyOfAnyType");
assertEquals(schema11.getAnyOf().size(), 6);

Schema schema13 = openAPI.getComponents().getSchemas().get("OneOfAnyType");
assertEquals(schema13.getOneOf().size(), 6);

Map<String, String> options = new HashMap<>();
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
openAPINormalizer.normalize();

Schema schema3 = openAPI.getComponents().getSchemas().get("AnyOfTest");
assertNull(schema3.getAnyOf());
assertEquals(ModelUtils.getType(schema3), "string");
assertTrue(schema3.getNullable());

Schema schema4 = openAPI.getComponents().getSchemas().get("OneOfTest");
assertNull(schema4.getOneOf());
assertEquals(ModelUtils.getType(schema4), "integer");
assertTrue(schema4.getNullable());

Schema schema4b = openAPI.getComponents().getSchemas().get("OneOfTest2");
assertNull(schema4b.getOneOf());
assertEquals(ModelUtils.getType(schema4b), "string");
assertTrue(schema4b.getNullable());

Schema schema6 = openAPI.getComponents().getSchemas().get("OneOfNullableTest");
assertEquals(schema6.getOneOf().size(), 2);
assertTrue(schema6.getNullable());

Schema schema8 = openAPI.getComponents().getSchemas().get("Parent");
assertEquals(((Schema) schema8.getProperties().get("number")).get$ref(), "#/components/schemas/Number");

Schema schema10 = openAPI.getComponents().getSchemas().get("AnyOfStringArrayOfString");
assertEquals(schema10.getAnyOf().size(), 2);

Schema schema12 = openAPI.getComponents().getSchemas().get("AnyOfAnyType");
assertEquals(schema12.getAnyOf(), null);
assertEquals(schema12.getType(), null);

Schema schema14 = openAPI.getComponents().getSchemas().get("OneOfAnyType");
assertEquals(schema14.getOneOf(), null);
assertEquals(schema14.getType(), null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ components:
- type: 'null'
- type: null
- $ref: null
OneOfTest2:
description: to test oneOf
oneOf:
- type: string
- type: 'null'
OneOfNullableTest:
description: to test oneOf nullable
oneOf:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
openapi: 3.1.0
info:
version: 1.0.0
title: Example
license:
name: MIT
servers:
- url: http://api.example.xyz/v1
paths:
/person/display/{personId}:
get:
parameters:
- name: personId
in: path
required: true
description: The id of the person to retrieve
schema:
type: string
operationId: list
responses:
'200':
description: OK
content:
application/json:
schema:
$ref: "#/components/schemas/AnyOfTest"
components:
schemas:
AnyOfTest:
description: to test anyOf
anyOf:
- type: string
- type: 'null'
- type: null
- $ref: null
OneOfTest:
description: to test oneOf
oneOf:
- type: integer
- type: 'null'
- type: null
- $ref: null
OneOfTest2:
description: to test oneOf
oneOf:
- type: string
- type: 'null'
OneOfNullableTest:
description: to test oneOf nullable
oneOf:
- type: integer
- type: string
- $ref: null
SingleAnyOfTest:
description: to test anyOf (enum string only)
anyOf:
- type: string
enum:
- A
- B
Parent:
type: object
properties:
number:
anyOf:
- $ref: '#/components/schemas/Number'
ParentWithOneOfProperty:
type: object
properties:
number:
oneOf:
- $ref: '#/components/schemas/Number'
ParentWithPluralOneOfProperty:
type: object
properties:
number:
oneOf:
- $ref: '#/components/schemas/Number'
- $ref: '#/components/schemas/Number2'
Number:
enum:
- one
- two
- three
type: string
Number2:
enum:
- one
- two
type: string
AnyOfStringArrayOfString:
anyOf:
- type: string
- type: array
items:
type: string
AnyOfAnyType:
anyOf:
- type: boolean
- type: array
items: {}
- type: object
- type: string
- type: number
- type: integer
OneOfAnyType:
oneOf:
- type: object
- type: boolean
- type: number
- type: string
- type: integer
- type: array
items: {}
Loading