From 2f6db3fecdf89e3878af48eb165bf12440969270 Mon Sep 17 00:00:00 2001 From: jpfinne Date: Sat, 13 Jun 2026 18:15:42 +0200 Subject: [PATCH 1/3] fix 23997: ensure that no JsonTypeName is created when the parent interface has a discriminator mapping --- .../openapitools/codegen/DefaultCodegen.java | 6 ++ .../java/spring/SpringCodegenTest.java | 15 ++++ .../resources/3_0/spring/issue_24003.yaml | 68 +++++++++++++++++++ 3 files changed, 89 insertions(+) create mode 100644 modules/openapi-generator/src/test/resources/3_0/spring/issue_24003.yaml diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index d000cde76814..78ab3387d41c 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -574,6 +574,12 @@ public Map postProcessAllModels(Map objs) } // if this is oneOf interface, make sure we include the necessary imports for it addImportsToOneOfInterface(modelsImports); + // + // ensure that no JsonTypeName is created when the parent interface has a discriminator mapping + if (cm.discriminator != null && cm.discriminator.getMappedModels().size() > 0) { + cm.discriminator.getMappedModels().forEach(mappedModel -> + mappedModel.getModel().setHasDiscriminatorWithNonEmptyMapping(true)); + } } } } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index 14b541cf9f0c..98f2817e31bc 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -8132,4 +8132,19 @@ void schemaMappingWithNullableAllOfRendersNullableJavaProperty() throws IOExcept JavaFileAssert.assertThat(files.get("MyObject.java")) .assertProperty("optionalRef").withType("JsonNullable"); } + + @Test + void issue24003() throws IOException { + Map files = generateFromContract( + "src/test/resources/3_0/spring/issue_24003.yaml", SPRING_BOOT, + Map.of(USE_SPRING_BOOT4, true, MODEL_NAME_SUFFIX, "DTO", INTERFACE_ONLY, "true")); + JavaFileAssert.assertThat(files.get("BrLockDTO.java")).isInterface() + .assertTypeAnnotations().containsWithName("JsonSubTypes") + .recursivelyContainsWithNameAndAttributes("JsonSubTypes.Type", Map.of("value", "ComponentBrLockDTO.class", "name", "\"COMPONENT\"")) + .recursivelyContainsWithNameAndAttributes("JsonSubTypes.Type", Map.of("value", "UserBrLockDTO.class", "name", "\"USER\"")); + JavaFileAssert.assertThat(files.get("ComponentBrLockDTO.java")).implementsInterfaces("BrLockDTO") + .fileDoesNotContain("@JsonTypeName"); + JavaFileAssert.assertThat(files.get("UserBrLockDTO.java")).implementsInterfaces("BrLockDTO") + .fileDoesNotContain("@JsonTypeName"); + } } \ No newline at end of file diff --git a/modules/openapi-generator/src/test/resources/3_0/spring/issue_24003.yaml b/modules/openapi-generator/src/test/resources/3_0/spring/issue_24003.yaml new file mode 100644 index 000000000000..21a6cc06ae30 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/spring/issue_24003.yaml @@ -0,0 +1,68 @@ +openapi: 3.0.1 +info: + title: x-discriminator-value JsonTypeName bug + version: 1.0.0 +paths: + /locks: + get: + operationId: getLocks + responses: + '200': + description: list of locks + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/BrLock' +components: + schemas: + LockType: + type: string + enum: + - USER + - COMPONENT + + BrLock: + type: object + required: + - lockType + properties: + lockType: + $ref: '#/components/schemas/LockType' + oneOf: + - $ref: '#/components/schemas/UserBrLock' + - $ref: '#/components/schemas/ComponentBrLock' + discriminator: + propertyName: lockType + mapping: + USER: '#/components/schemas/UserBrLock' + COMPONENT: '#/components/schemas/ComponentBrLock' + + BaseBrLock: + type: object + required: + - lockType + properties: + lockType: + $ref: '#/components/schemas/LockType' + + UserBrLock: + allOf: + - $ref: '#/components/schemas/BaseBrLock' + - type: object + required: + - userId + properties: + userId: + type: string + + ComponentBrLock: + allOf: + - $ref: '#/components/schemas/BaseBrLock' + - type: object + required: + - componentId + properties: + componentId: + type: string \ No newline at end of file From f11be058e7278e768d51178b8c979dc485d35f50 Mon Sep 17 00:00:00 2001 From: jpfinne Date: Sun, 14 Jun 2026 16:10:22 +0200 Subject: [PATCH 2/3] add test for @JsonTypeInfo --- .../openapitools/codegen/java/spring/SpringCodegenTest.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java index 98f2817e31bc..c46b8dfdfa10 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java @@ -8139,7 +8139,9 @@ void issue24003() throws IOException { "src/test/resources/3_0/spring/issue_24003.yaml", SPRING_BOOT, Map.of(USE_SPRING_BOOT4, true, MODEL_NAME_SUFFIX, "DTO", INTERFACE_ONLY, "true")); JavaFileAssert.assertThat(files.get("BrLockDTO.java")).isInterface() - .assertTypeAnnotations().containsWithName("JsonSubTypes") + .assertTypeAnnotations() + .containsWithNameAndAttributes("JsonTypeInfo", Map.of("use", "JsonTypeInfo.Id.NAME", "include", "JsonTypeInfo.As.PROPERTY", "property", "\"lockType\"", "visible", "true")) + .containsWithName("JsonSubTypes") .recursivelyContainsWithNameAndAttributes("JsonSubTypes.Type", Map.of("value", "ComponentBrLockDTO.class", "name", "\"COMPONENT\"")) .recursivelyContainsWithNameAndAttributes("JsonSubTypes.Type", Map.of("value", "UserBrLockDTO.class", "name", "\"USER\"")); JavaFileAssert.assertThat(files.get("ComponentBrLockDTO.java")).implementsInterfaces("BrLockDTO") From dc0d05b6dc1c3634fec640bc4e89693bbdd3cdd3 Mon Sep 17 00:00:00 2001 From: jpfinne Date: Sun, 14 Jun 2026 17:05:20 +0200 Subject: [PATCH 3/3] Fix Cubic findings --- .../java/org/openapitools/codegen/DefaultCodegen.java | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 78ab3387d41c..97e6d8735e43 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -576,9 +576,11 @@ public Map postProcessAllModels(Map objs) addImportsToOneOfInterface(modelsImports); // // ensure that no JsonTypeName is created when the parent interface has a discriminator mapping - if (cm.discriminator != null && cm.discriminator.getMappedModels().size() > 0) { - cm.discriminator.getMappedModels().forEach(mappedModel -> - mappedModel.getModel().setHasDiscriminatorWithNonEmptyMapping(true)); + if (cm.discriminator != null && cm.discriminator.getMappedModels() != null && !cm.discriminator.getMappedModels().isEmpty()) { + cm.discriminator.getMappedModels().stream() + .map(MappedModel::getModel) + .filter(Objects::nonNull) + .forEach(model -> model.setHasDiscriminatorWithNonEmptyMapping(true)); } } }