Skip to content

Commit 1d7d399

Browse files
authored
fix additional properties handling in 3.1 spec (#22056)
1 parent 4121803 commit 1d7d399

File tree

5 files changed

+182
-3
lines changed

5 files changed

+182
-3
lines changed

modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -724,15 +724,17 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
724724
if (skipNormalization(schema, visitedSchemas)) {
725725
return schema;
726726
}
727+
728+
if (ModelUtils.isNullTypeSchema(openAPI, schema)) {
729+
return schema;
730+
}
731+
727732
markSchemaAsVisited(schema, visitedSchemas);
728733

729734
if (ModelUtils.isArraySchema(schema)) { // array
730735
Schema result = normalizeArraySchema(schema);
731736
normalizeSchema(result.getItems(), visitedSchemas);
732737
return result;
733-
} else if (schema.getAdditionalProperties() instanceof Schema) { // map
734-
normalizeMapSchema(schema);
735-
normalizeSchema((Schema) schema.getAdditionalProperties(), visitedSchemas);
736738
} else if (ModelUtils.isOneOf(schema)) { // oneOf
737739
return normalizeOneOf(schema, visitedSchemas);
738740
} else if (ModelUtils.isAnyOf(schema)) { // anyOf
@@ -769,6 +771,9 @@ public Schema normalizeSchema(Schema schema, Set<Schema> visitedSchemas) {
769771
return schema;
770772
} else if (schema.getProperties() != null && !schema.getProperties().isEmpty()) {
771773
normalizeProperties(schema.getProperties(), visitedSchemas);
774+
} else if (schema.getAdditionalProperties() instanceof Schema) { // map
775+
normalizeMapSchema(schema);
776+
normalizeSchema((Schema) schema.getAdditionalProperties(), visitedSchemas);
772777
} else if (schema instanceof BooleanSchema) {
773778
normalizeBooleanSchema(schema, visitedSchemas);
774779
} else if (schema instanceof IntegerSchema) {
@@ -1012,6 +1017,7 @@ protected Schema normalizeAnyOf(Schema schema, Set<Schema> visitedSchemas) {
10121017
if (schema.getAnyOf() == null) {
10131018
return schema;
10141019
}
1020+
10151021
for (int i = 0; i < schema.getAnyOf().size(); i++) {
10161022
// normalize anyOf sub schemas one by one
10171023
Object item = schema.getAnyOf().get(i);

modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,11 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
971971
Schema schema21 = openAPI.getComponents().getSchemas().get("SingleAnyOfTest");
972972
assertEquals(schema21.getAnyOf().size(), 1);
973973

974+
Schema schema23 = openAPI.getComponents().getSchemas().get("PropertiesWithAnyOf");
975+
assertEquals(((Schema) schema23.getProperties().get("anyof_nullable_string")).getAnyOf().size(), 2);
976+
assertEquals(((Schema) schema23.getProperties().get("anyof_nullable_number")).getAnyOf().size(), 2);
977+
978+
// start the normalization
974979
Map<String, String> options = new HashMap<>();
975980
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
976981
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
@@ -1025,6 +1030,14 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
10251030
assertEquals(schema22.getAnyOf(), null);
10261031
assertEquals(schema22.getTypes(), Set.of("string"));
10271032
assertEquals(schema22.getEnum().size(), 2);
1033+
1034+
Schema schema24 = openAPI.getComponents().getSchemas().get("PropertiesWithAnyOf");
1035+
assertEquals(((Schema) schema24.getProperties().get("anyof_nullable_string")).getAnyOf(), null);
1036+
assertEquals(((Schema) schema24.getProperties().get("anyof_nullable_string")).getNullable(), true);
1037+
assertEquals(((Schema) schema24.getProperties().get("anyof_nullable_string")).getTypes().size(), 1);
1038+
assertEquals(((Schema) schema24.getProperties().get("anyof_nullable_number")).getAnyOf(), null);
1039+
assertEquals(((Schema) schema24.getProperties().get("anyof_nullable_number")).getNullable(), true);
1040+
assertEquals(((Schema) schema24.getProperties().get("anyof_nullable_number")).getTypes().size(), 1);
10281041
}
10291042

10301043
@Test

modules/openapi-generator/src/test/java/org/openapitools/codegen/utils/ModelUtilsTest.java

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -623,6 +623,47 @@ public void isNullTypeSchemaTest() {
623623
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
624624
}
625625

626+
@Test
627+
public void isNullTypeSchemaTestWith31Spec() {
628+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/null_schema_test.yaml");
629+
Map<String, String> options = new HashMap<>();
630+
Schema schema = openAPI.getComponents().getSchemas().get("AnyOfStringArrayOfString");
631+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
632+
633+
schema = openAPI.getComponents().getSchemas().get("IntegerRef");
634+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
635+
636+
schema = openAPI.getComponents().getSchemas().get("OneOfAnyType");
637+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
638+
639+
schema = openAPI.getComponents().getSchemas().get("AnyOfAnyType");
640+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
641+
642+
schema = openAPI.getComponents().getSchemas().get("Parent");
643+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
644+
// the dummy property is a ref to integer
645+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, (Schema) schema.getProperties().get("dummy")));
646+
647+
schema = openAPI.getComponents().getSchemas().get("AnyOfTest");
648+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
649+
// first element (getAnyOf().get(0)) is a string. no need to test
650+
assertTrue(ModelUtils.isNullTypeSchema(openAPI, (Schema) schema.getAnyOf().get(1)));
651+
assertTrue(ModelUtils.isNullTypeSchema(openAPI, (Schema) schema.getAnyOf().get(2)));
652+
assertTrue(ModelUtils.isNullTypeSchema(openAPI, (Schema) schema.getAnyOf().get(3)));
653+
654+
schema = openAPI.getComponents().getSchemas().get("OneOfRef");
655+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
656+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, (Schema) schema.getOneOf().get(0)));
657+
658+
schema = openAPI.getComponents().getSchemas().get("OneOfMultiRef");
659+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
660+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, (Schema) schema.getOneOf().get(0)));
661+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, (Schema) schema.getOneOf().get(1)));
662+
663+
schema = openAPI.getComponents().getSchemas().get("JustDescription");
664+
assertFalse(ModelUtils.isNullTypeSchema(openAPI, schema));
665+
}
666+
626667
@Test
627668
public void isUnsupportedSchemaTest() {
628669
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/unsupported_schema_test.yaml");
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
openapi: 3.1.0
2+
info:
3+
version: 1.0.0
4+
title: Example
5+
license:
6+
name: MIT
7+
servers:
8+
- url: http://api.example.xyz/v1
9+
paths:
10+
/person/display/{personId}:
11+
get:
12+
parameters:
13+
- name: personId
14+
in: path
15+
required: true
16+
description: The id of the person to retrieve
17+
schema:
18+
type: string
19+
operationId: list
20+
responses:
21+
'200':
22+
description: OK
23+
content:
24+
application/json:
25+
schema:
26+
$ref: "#/components/schemas/AnyOfTest"
27+
components:
28+
schemas:
29+
AnyOfTest:
30+
description: to test anyOf
31+
anyOf:
32+
- type: string
33+
- type: 'null'
34+
- type: null
35+
- $ref: null
36+
OneOfTest:
37+
description: to test oneOf
38+
oneOf:
39+
- type: integer
40+
- type: 'null'
41+
- type: null
42+
- $ref: null
43+
OneOfTest2:
44+
description: to test oneOf
45+
oneOf:
46+
- type: string
47+
- type: 'null'
48+
OneOfNullableTest:
49+
description: to test oneOf nullable
50+
oneOf:
51+
- type: integer
52+
- type: string
53+
- $ref: null
54+
Parent:
55+
type: object
56+
properties:
57+
dummy:
58+
$ref: '#/components/schemas/IntegerRef'
59+
string_ref:
60+
anyOf:
61+
- $ref: '#/components/schemas/StringRef'
62+
AnyOfStringArrayOfString:
63+
anyOf:
64+
- type: string
65+
- type: array
66+
items:
67+
type: string
68+
AnyOfAnyType:
69+
anyOf:
70+
- type: boolean
71+
- type: array
72+
items: {}
73+
- type: object
74+
- type: string
75+
- type: number
76+
- type: integer
77+
AnyOfAnyTypeWithRef:
78+
anyOf:
79+
- type: boolean
80+
- type: array
81+
items: { }
82+
- type: object
83+
- type: string
84+
- type: number
85+
- $ref: '#/components/schemas/IntegerRef'
86+
IntegerRef:
87+
type: integer
88+
StringRef:
89+
type: string
90+
OneOfAnyType:
91+
oneOf:
92+
- type: object
93+
- type: boolean
94+
- type: number
95+
- type: string
96+
- type: integer
97+
- type: array
98+
items: {}
99+
OneOfRef:
100+
oneOf:
101+
- $ref: '#/components/schemas/IntegerRef'
102+
OneOfMultiRef:
103+
oneOf:
104+
- $ref: '#/components/schemas/IntegerRef'
105+
- $ref: '#/components/schemas/StringRef'
106+
JustDescription:
107+
description: A schema with just description

modules/openapi-generator/src/test/resources/3_1/simplifyOneOfAnyOf_test.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,18 @@ components:
7777
oneOf:
7878
- $ref: '#/components/schemas/Number'
7979
- $ref: '#/components/schemas/Number2'
80+
PropertiesWithAnyOf:
81+
additionalProperties: false
82+
type: object
83+
properties:
84+
anyof_nullable_string:
85+
anyOf:
86+
- type: string
87+
- type: null
88+
anyof_nullable_number:
89+
anyOf:
90+
- type: number
91+
- type: null
8092
Number:
8193
enum:
8294
- one

0 commit comments

Comments
 (0)