From a0dcea196a65c0d02c4004dec875b901ca9c9509 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=9Apiewak?= Date: Thu, 29 Jan 2026 17:47:21 +0100 Subject: [PATCH 1/2] Add const type inference to 3.1 normalization --- .../codegen/OpenAPINormalizer.java | 21 +++++++++++----- .../codegen/utils/ModelUtils.java | 4 ++++ .../codegen/OpenAPINormalizerTest.java | 17 +++++++++++++ .../resources/3_1/const-type-inference.yaml | 24 +++++++++++++++++++ 4 files changed, 60 insertions(+), 6 deletions(-) create mode 100644 modules/openapi-generator/src/test/resources/3_1/const-type-inference.yaml diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java index d396acc8566f..9102fd5bb41d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java @@ -1782,6 +1782,21 @@ protected Schema processNormalize31Spec(Schema schema, Set visitedSchema return null; } + // process const + if (schema.getConst() != null) { + Object value = schema.getConst(); + schema.setEnum(Arrays.asList(value)); + schema.setConst(null); + + if (schema.getTypes() == null) { + if (value instanceof String) { + schema.addType("string"); + } else if (value instanceof Integer) { + schema.addType("integer"); + } + } + } + if (schema instanceof JsonSchema && schema.get$schema() == null && schema.getTypes() == null && schema.getType() == null) { @@ -1803,12 +1818,6 @@ protected Schema processNormalize31Spec(Schema schema, Set visitedSchema schema.getTypes().remove("null"); } - // process const - if (schema.getConst() != null) { - schema.setEnum(Arrays.asList(schema.getConst())); - schema.setConst(null); - } - // only one item (type) left if (schema.getTypes().size() == 1) { String type = String.valueOf(schema.getTypes().iterator().next()); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java index a8f62b1b8331..5a67339fcaf3 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java @@ -2334,6 +2334,10 @@ public static boolean isNullTypeSchema(OpenAPI openAPI, Schema schema) { } } + if (schema.getConst() != null) { + return false; + } + if (schema.getTypes() != null && !schema.getTypes().isEmpty()) { // 3.1 spec if (schema.getTypes().size() == 1) { // 1 type only diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java index e38373e8d81c..0226a24e7dc4 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java @@ -1180,6 +1180,23 @@ public void testOpenAPINormalizerSingleConstEnum31Spec() { assertEquals(Arrays.asList(originalConst), normalizedTypeSchema.getEnum()); } + @Test + public void testOpenAPINormalizerConstTypeInference31Spec() { + OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/const-type-inference.yaml"); + + assertNotEquals( + openAPI.getComponents().getSchemas().get("ConstStyle"), + openAPI.getComponents().getSchemas().get("EnumStyle") + ); + + new OpenAPINormalizer(openAPI, Map.of("NORMALIZE_31SPEC", "true")).normalize(); + + assertEquals( + openAPI.getComponents().getSchemas().get("ConstStyle"), + openAPI.getComponents().getSchemas().get("EnumStyle") + ); + } + @Test public void testOpenAPINormalizerProcessingAllOfSchema31Spec() { // to test array schema processing in 3.1 spec diff --git a/modules/openapi-generator/src/test/resources/3_1/const-type-inference.yaml b/modules/openapi-generator/src/test/resources/3_1/const-type-inference.yaml new file mode 100644 index 000000000000..561860737b82 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_1/const-type-inference.yaml @@ -0,0 +1,24 @@ +openapi: 3.1.0 +info: + title: "Const Type Inference Test" + version: 1.0.0 +components: + schemas: + ConstStyle: + type: object + properties: + stringValue: + const: "hello-world" + intValue: + const: 42 + EnumStyle: + type: object + properties: + stringValue: + type: string + enum: + - "hello-world" + intValue: + type: integer + enum: + - 42 From da3fa6b6648a8cc32b3364f429d6ffe430e8b125 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20=C5=9Apiewak?= Date: Mon, 16 Feb 2026 19:31:22 +0100 Subject: [PATCH 2/2] Normalize oneOf subschemas before normalizing the oneOf --- .../codegen/OpenAPINormalizer.java | 34 +++++++------------ .../codegen/OpenAPINormalizerTest.java | 20 +++++++++++ .../src/test/resources/3_1/oneof-const.yaml | 22 ++++++++++++ 3 files changed, 55 insertions(+), 21 deletions(-) create mode 100644 modules/openapi-generator/src/test/resources/3_1/oneof-const.yaml diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java index 9102fd5bb41d..fc63bfb970dd 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/OpenAPINormalizer.java @@ -1037,32 +1037,25 @@ protected Schema normalizeAllOfWithProperties(Schema schema, Set visited } protected Schema normalizeOneOf(Schema schema, Set visitedSchemas) { + List oneOfSchemas = schema.getOneOf(); + + if (oneOfSchemas == null) { + return schema; + } + + oneOfSchemas = oneOfSchemas.stream() + .map(subSchema -> normalizeSchema(subSchema, visitedSchemas)) + .collect(Collectors.toCollection(ArrayList::new)); + + schema.setOneOf(oneOfSchemas); + // Remove duplicate oneOf entries ModelUtils.deduplicateOneOfSchema(schema); schema = processSimplifyOneOfEnum(schema); - - // simplify first as the schema may no longer be a oneOf after processing the rule below schema = processSimplifyOneOf(schema); - // if it's still a oneOf, loop through the sub-schemas - if (schema.getOneOf() != null) { - 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); - } - - // update sub-schema with the updated schema - schema.getOneOf().set(i, normalizeSchema((Schema) item, visitedSchemas)); - } - } else { - // normalize it as it's no longer an oneOf + if (schema.getOneOf() == null) { schema = normalizeSchema(schema, visitedSchemas); } @@ -1551,7 +1544,6 @@ protected Schema processSimplifyOneOf(Schema schema) { schema = simplifyOneOfAnyOfWithOnlyOneNonNullSubSchema(openAPI, schema, oneOfSchemas); if (ModelUtils.isIntegerSchema(schema) || ModelUtils.isNumberSchema(schema) || ModelUtils.isStringSchema(schema)) { - // TODO convert oneOf const to enum schema.setOneOf(null); } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java index 0226a24e7dc4..57302cfb0e5e 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/OpenAPINormalizerTest.java @@ -1197,6 +1197,26 @@ public void testOpenAPINormalizerConstTypeInference31Spec() { ); } + @Test + public void testOpenAPINormalizerOneOfConst31Spec() { + OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_1/oneof-const.yaml"); + + assertNotEquals( + openAPI.getComponents().getSchemas().get("OneOfConst"), + openAPI.getComponents().getSchemas().get("Enum") + ); + + new OpenAPINormalizer( + openAPI, + Map.of("NORMALIZE_31SPEC", "true", "SIMPLIFY_ONEOF_ANYOF_ENUM", "true") + ).normalize(); + + assertEquals( + openAPI.getComponents().getSchemas().get("OneOfConst"), + openAPI.getComponents().getSchemas().get("Enum") + ); + } + @Test public void testOpenAPINormalizerProcessingAllOfSchema31Spec() { // to test array schema processing in 3.1 spec diff --git a/modules/openapi-generator/src/test/resources/3_1/oneof-const.yaml b/modules/openapi-generator/src/test/resources/3_1/oneof-const.yaml new file mode 100644 index 000000000000..3212bb544719 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_1/oneof-const.yaml @@ -0,0 +1,22 @@ +openapi: 3.1.0 +info: + title: "OneOf const to enum normalization" + version: 1.0.0 +components: + schemas: + OneOfConst: + oneOf: + - const: foo + - const: bar + description: This is bar + - const: baz + Enum: + type: string + enum: + - foo + - bar + - baz + x-enum-descriptions: + - "" + - This is bar + - ""