Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 99f63e8

Browse files
committedApr 6, 2025·
Fixes so that a oneOf schema with a single sub-schema is simplified when SIMPLIFY_ONEOF_ANYOF is set to true
1 parent 9bac318 commit 99f63e8

File tree

4 files changed

+137
-28
lines changed

4 files changed

+137
-28
lines changed
 

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

+3-22
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import java.util.function.Function;
3737
import java.util.stream.Collectors;
3838

39+
import static org.openapitools.codegen.utils.ModelUtils.simplyOneOfAnyOfWithOnlyOneNonNullSubSchema;
3940
import static org.openapitools.codegen.utils.StringUtils.getUniqueString;
4041

4142
public class OpenAPINormalizer {
@@ -1213,17 +1214,7 @@ private Schema processSimplifyOneOf(Schema schema) {
12131214
}
12141215
}
12151216

1216-
if (oneOfSchemas.removeIf(oneOf -> ModelUtils.isNullTypeSchema(openAPI, oneOf))) {
1217-
schema.setNullable(true);
1218-
1219-
// if only one element left, simplify to just the element (schema)
1220-
if (oneOfSchemas.size() == 1) {
1221-
if (Boolean.TRUE.equals(schema.getNullable())) { // retain nullable setting
1222-
((Schema) oneOfSchemas.get(0)).setNullable(true);
1223-
}
1224-
return (Schema) oneOfSchemas.get(0);
1225-
}
1226-
}
1217+
schema = simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, schema, oneOfSchemas);
12271218

12281219
if (ModelUtils.isIntegerSchema(schema) || ModelUtils.isNumberSchema(schema) || ModelUtils.isStringSchema(schema)) {
12291220
// TODO convert oneOf const to enum
@@ -1350,17 +1341,7 @@ private Schema processSimplifyAnyOf(Schema schema) {
13501341
}
13511342
}
13521343

1353-
if (anyOfSchemas.removeIf(anyOf -> ModelUtils.isNullTypeSchema(openAPI, anyOf))) {
1354-
schema.setNullable(true);
1355-
}
1356-
1357-
// if only one element left, simplify to just the element (schema)
1358-
if (anyOfSchemas.size() == 1) {
1359-
if (Boolean.TRUE.equals(schema.getNullable())) { // retain nullable setting
1360-
((Schema) anyOfSchemas.get(0)).setNullable(true);
1361-
}
1362-
return (Schema) anyOfSchemas.get(0);
1363-
}
1344+
schema = simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, schema, anyOfSchemas);
13641345
}
13651346

13661347
return schema;

‎modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java

+24
Original file line numberDiff line numberDiff line change
@@ -2219,6 +2219,30 @@ public static Schema cloneSchema(Schema schema, boolean openapi31) {
22192219
}
22202220
}
22212221

2222+
/**
2223+
* Simplifies the schema by removing the oneOfAnyOf if the oneOfAnyOf only contains a single non-null sub-schema
2224+
*
2225+
* @param openAPI OpenAPI
2226+
* @param schema Schema
2227+
* @param subSchemas The oneOf or AnyOf schemas
2228+
* @return The simplified schema
2229+
*/
2230+
public static Schema simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(OpenAPI openAPI, Schema schema, List<Schema> subSchemas) {
2231+
if (subSchemas.removeIf(subSchema -> isNullTypeSchema(openAPI, subSchema))) {
2232+
schema.setNullable(true);
2233+
}
2234+
2235+
// if only one element left, simplify to just the element (schema)
2236+
if (subSchemas.size() == 1) {
2237+
if (Boolean.TRUE.equals(schema.getNullable())) { // retain nullable setting
2238+
subSchemas.get(0).setNullable(true);
2239+
}
2240+
return subSchemas.get(0);
2241+
}
2242+
2243+
return schema;
2244+
}
2245+
22222246
/**
22232247
* Check if the schema is of type 'null' or schema itself is pointing to null
22242248
* <p>

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

+61-4
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,7 @@
2424
import org.openapitools.codegen.utils.ModelUtils;
2525
import org.testng.annotations.Test;
2626

27-
import java.util.Arrays;
28-
import java.util.Collections;
29-
import java.util.HashMap;
30-
import java.util.Map;
27+
import java.util.*;
3128

3229
import static org.testng.Assert.*;
3330

@@ -171,6 +168,12 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf() {
171168
Schema schema15 = openAPI.getComponents().getSchemas().get("AnyOfAnyTypeWithRef");
172169
assertEquals(schema15.getAnyOf().size(), 6);
173170

171+
Schema schema17 = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
172+
assertEquals(((Schema) schema17.getProperties().get("number")).getOneOf().size(), 1);
173+
174+
Schema schema19 = openAPI.getComponents().getSchemas().get("SingleAnyOfTest");
175+
assertEquals(schema19.getAnyOf().size(), 1);
176+
174177
Map<String, String> options = new HashMap<>();
175178
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
176179
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
@@ -212,6 +215,30 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf() {
212215
Schema schema16 = openAPI.getComponents().getSchemas().get("AnyOfAnyTypeWithRef");
213216
assertEquals(schema16.getAnyOf(), null);
214217
assertEquals(schema16.getType(), null);
218+
219+
Schema schema18 = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
220+
assertEquals(((Schema) schema18.getProperties().get("number")).get$ref(), "#/components/schemas/Number");
221+
222+
Schema schema20 = openAPI.getComponents().getSchemas().get("SingleAnyOfTest");
223+
assertEquals(schema20.getAnyOf(), null);
224+
assertEquals(schema20.getType(), "string");
225+
assertEquals(schema20.getEnum().size(), 2);
226+
}
227+
228+
@Test
229+
public void testOpenAPINormalizerSimplifyOneOfWithSingleRef() {
230+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/simplifyOneOfAnyOf_test.yaml");
231+
232+
Schema oneOfWithSingleRef = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
233+
assertEquals(((Schema) oneOfWithSingleRef.getProperties().get("number")).getOneOf().size(), 1);
234+
235+
Map<String, String> options = new HashMap<>();
236+
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
237+
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
238+
openAPINormalizer.normalize();
239+
240+
oneOfWithSingleRef = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
241+
assertEquals(((Schema) oneOfWithSingleRef.getProperties().get("number")).get$ref(), "#/components/schemas/Number");
215242
}
216243

217244
@Test
@@ -833,6 +860,12 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
833860
Schema schema17 = openAPI.getComponents().getSchemas().get("OneOfNullAndRef3");
834861
assertEquals(schema17.getOneOf().size(), 2);
835862

863+
Schema schema19 = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
864+
assertEquals(((Schema) schema19.getProperties().get("number")).getOneOf().size(), 1);
865+
866+
Schema schema21 = openAPI.getComponents().getSchemas().get("SingleAnyOfTest");
867+
assertEquals(schema21.getAnyOf().size(), 1);
868+
836869
Map<String, String> options = new HashMap<>();
837870
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
838871
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
@@ -879,6 +912,30 @@ public void testOpenAPINormalizerSimplifyOneOfAnyOf31Spec() {
879912
// original oneOf removed and simplified to just $ref (oneOf sub-schema) instead
880913
assertEquals(schema18.getOneOf(), null);
881914
assertEquals(schema18.get$ref(), "#/components/schemas/Parent");
915+
916+
Schema schema20 = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
917+
assertEquals(((Schema) schema20.getProperties().get("number")).get$ref(), "#/components/schemas/Number");
918+
919+
Schema schema22 = openAPI.getComponents().getSchemas().get("SingleAnyOfTest");
920+
assertEquals(schema22.getAnyOf(), null);
921+
assertEquals(schema22.getTypes(), Set.of("string"));
922+
assertEquals(schema22.getEnum().size(), 2);
923+
}
924+
925+
@Test
926+
public void testOpenAPINormalizerSimplifyOneOfWithSingleRef31Spec() {
927+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/simplifyOneOfAnyOf_test.yaml");
928+
929+
Schema oneOfWithSingleRef = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
930+
assertEquals(((Schema) oneOfWithSingleRef.getProperties().get("number")).getOneOf().size(), 1);
931+
932+
Map<String, String> options = new HashMap<>();
933+
options.put("SIMPLIFY_ONEOF_ANYOF", "true");
934+
OpenAPINormalizer openAPINormalizer = new OpenAPINormalizer(openAPI, options);
935+
openAPINormalizer.normalize();
936+
937+
oneOfWithSingleRef = openAPI.getComponents().getSchemas().get("ParentWithOneOfProperty");
938+
assertEquals(((Schema) oneOfWithSingleRef.getProperties().get("number")).get$ref(), "#/components/schemas/Number");
882939
}
883940

884941
@Test

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

+49-2
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@
3232
import java.util.List;
3333
import java.util.Map;
3434

35-
import static org.testng.Assert.assertFalse;
36-
import static org.testng.Assert.assertTrue;
35+
import static org.testng.Assert.*;
3736

3837
public class ModelUtilsTest {
3938

@@ -476,6 +475,54 @@ public void testGetSchemaItemsWith31Spec() {
476475
Assert.assertNotNull(ModelUtils.getSchemaItems((Schema) arrayWithPrefixItems.getProperties().get("without_items")));
477476
}
478477

478+
@Test
479+
public void simplyOneOfAnyOfWithOnlyOneNonNullSubSchema() {
480+
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/simplifyOneOfAnyOf_test.yaml");
481+
Schema schema;
482+
List<Schema> subSchemas;
483+
484+
Schema anyOfWithSeveralSubSchemasButSingleNonNull = ModelUtils.getSchema(openAPI, "AnyOfTest");
485+
subSchemas = anyOfWithSeveralSubSchemasButSingleNonNull.getAnyOf();
486+
schema = ModelUtils.simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, anyOfWithSeveralSubSchemasButSingleNonNull, subSchemas);
487+
assertNull(schema.getOneOf());
488+
assertNull(schema.getAnyOf());
489+
assertTrue(schema.getNullable());
490+
assertEquals("string", schema.getType());
491+
492+
Schema anyOfWithSingleNonNullSubSchema = ModelUtils.getSchema(openAPI, "Parent");
493+
subSchemas = ((Schema) anyOfWithSingleNonNullSubSchema.getProperties().get("number")).getAnyOf();
494+
schema = ModelUtils.simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, anyOfWithSingleNonNullSubSchema, subSchemas);
495+
assertNull(schema.getOneOf());
496+
assertNull(schema.getAnyOf());
497+
assertNull(schema.getNullable());
498+
assertEquals(schema.get$ref(), "#/components/schemas/Number");
499+
500+
Schema oneOfWithSeveralSubSchemasButSingleNonNull = ModelUtils.getSchema(openAPI, "OneOfTest");
501+
subSchemas = oneOfWithSeveralSubSchemasButSingleNonNull.getOneOf();
502+
schema = ModelUtils.simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, oneOfWithSeveralSubSchemasButSingleNonNull, subSchemas);
503+
assertNull(schema.getOneOf());
504+
assertNull(schema.getAnyOf());
505+
assertTrue(schema.getNullable());
506+
assertEquals("integer", schema.getType());
507+
508+
Schema oneOfWithSingleNonNullSubSchema = ModelUtils.getSchema(openAPI, "ParentWithOneOfProperty");
509+
subSchemas = ((Schema) oneOfWithSingleNonNullSubSchema.getProperties().get("number")).getOneOf();
510+
schema = ModelUtils.simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, oneOfWithSingleNonNullSubSchema, subSchemas);
511+
assertNull(schema.getOneOf());
512+
assertNull(schema.getAnyOf());
513+
assertNull(schema.getNullable());
514+
assertEquals(schema.get$ref(), "#/components/schemas/Number");
515+
516+
Schema oneOfWithSeveralSubSchemas = ModelUtils.getSchema(openAPI, "ParentWithPluralOneOfProperty");
517+
subSchemas = ((Schema) oneOfWithSeveralSubSchemas.getProperties().get("number")).getOneOf();
518+
schema = ModelUtils.simplyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, oneOfWithSeveralSubSchemas, subSchemas);
519+
assertNull(schema.getOneOf());
520+
assertNotNull(oneOfWithSeveralSubSchemas.getProperties().get("number"));
521+
assertNull(schema.getAnyOf());
522+
assertNull(schema.getNullable());
523+
assertEquals(((Schema) oneOfWithSeveralSubSchemas.getProperties().get("number")).getOneOf().size(), 2);
524+
}
525+
479526
@Test
480527
public void isNullTypeSchemaTest() {
481528
OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/null_schema_test.yaml");

0 commit comments

Comments
 (0)
Please sign in to comment.