diff --git a/modules/openapi-generator/src/main/resources/Java/pojo.mustache b/modules/openapi-generator/src/main/resources/Java/pojo.mustache index 3313a2cbdc3..e8d4dc8ee21 100644 --- a/modules/openapi-generator/src/main/resources/Java/pojo.mustache +++ b/modules/openapi-generator/src/main/resources/Java/pojo.mustache @@ -15,7 +15,9 @@ {{/vars}} }) {{#isClassnameSanitized}} +{{^hasDiscriminatorWithNonEmptyMapping}} @JsonTypeName("{{name}}") +{{/hasDiscriminatorWithNonEmptyMapping}} {{/isClassnameSanitized}} {{/jackson}} {{>additionalModelTypeAnnotations}}{{>generatedAnnotation}}{{#discriminator}}{{>typeInfoAnnotation}}{{/discriminator}}{{>xmlAnnotation}} diff --git a/modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache b/modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache index 6217ac15abf..a41cb8eac75 100644 --- a/modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache +++ b/modules/openapi-generator/src/main/resources/JavaSpring/pojo.mustache @@ -15,7 +15,9 @@ {{/discriminator}} {{#jackson}} {{#isClassnameSanitized}} +{{^hasDiscriminatorWithNonEmptyMapping}} @JsonTypeName("{{name}}") +{{/hasDiscriminatorWithNonEmptyMapping}} {{/isClassnameSanitized}} {{/jackson}} {{#withXml}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java index b046fd2a344..847eb43b263 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java @@ -18,6 +18,7 @@ package org.openapitools.codegen.java; import com.google.common.collect.ImmutableMap; +import io.swagger.parser.OpenAPIParser; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.media.ArraySchema; @@ -30,6 +31,7 @@ import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; import io.swagger.v3.oas.models.parameters.RequestBody; import io.swagger.v3.oas.models.responses.ApiResponse; +import io.swagger.v3.parser.core.models.ParseOptions; import io.swagger.v3.parser.util.SchemaTypeUtil; import org.openapitools.codegen.ClientOptInput; import org.openapitools.codegen.CodegenConstants; @@ -75,6 +77,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.stream.Collectors; +import static org.openapitools.codegen.TestUtils.assertFileContains; +import static org.openapitools.codegen.TestUtils.assertFileNotContains; import static org.openapitools.codegen.TestUtils.validateJavaSourceFiles; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; @@ -1752,4 +1756,82 @@ public class JavaClientCodegenTest { TestUtils.assertFileContains(Paths.get(output + "/src/main/java/xyz/abcdef/model/AnotherChild.java"), "public class AnotherChild {"); } + + @Test + public void testDiscriminatorWithMappingIssue14731() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + String outputPath = output.getAbsolutePath().replace('\\', '/'); + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_14731.yaml", null, new ParseOptions()).getOpenAPI(); + + JavaClientCodegen codegen = new JavaClientCodegen(); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true"); + codegen.setUseOneOfInterfaces(true); + + ClientOptInput input = new ClientOptInput(); + input.openAPI(openAPI); + input.config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, "false"); + + + codegen.setUseOneOfInterfaces(true); + codegen.setLegacyDiscriminatorBehavior(false); + codegen.setUseJakartaEe(true); + codegen.setModelNameSuffix("DTO"); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false"); + + generator.opts(input).generate(); + + assertFileNotContains(Paths.get(outputPath + "/src/main/java/org/openapitools/client/model/ChildWithMappingADTO.java"), "@JsonTypeName"); + assertFileNotContains(Paths.get(outputPath + "/src/main/java/org/openapitools/client/model/ChildWithMappingBDTO.java"), "@JsonTypeName"); + } + + @Test + public void testDiscriminatorWithoutMappingIssue14731() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + String outputPath = output.getAbsolutePath().replace('\\', '/'); + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_14731.yaml", null, new ParseOptions()).getOpenAPI(); + + JavaClientCodegen codegen = new JavaClientCodegen(); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true"); + codegen.setUseOneOfInterfaces(true); + + ClientOptInput input = new ClientOptInput(); + input.openAPI(openAPI); + input.config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, "false"); + + + codegen.setUseOneOfInterfaces(true); + codegen.setLegacyDiscriminatorBehavior(false); + codegen.setUseJakartaEe(true); + codegen.setModelNameSuffix("DTO"); + codegen.setLibrary(JavaClientCodegen.RESTTEMPLATE); + + + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false"); + + generator.opts(input).generate(); + + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/client/model/ChildWithoutMappingADTO.java"), "@JsonTypeName"); + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/client/model/ChildWithoutMappingBDTO.java"), "@JsonTypeName"); + } } 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 085e495bf91..f18c7a4cd5f 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 @@ -1141,6 +1141,85 @@ public class SpringCodegenTest { assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/PizzaSpeziale.java"), "import java.math.BigDecimal"); } + @Test + public void testDiscriminatorWithMappingIssue14731() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + String outputPath = output.getAbsolutePath().replace('\\', '/'); + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_14731.yaml", null, new ParseOptions()).getOpenAPI(); + + SpringCodegen codegen = new SpringCodegen(); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true"); + codegen.setUseOneOfInterfaces(true); + + ClientOptInput input = new ClientOptInput(); + input.openAPI(openAPI); + input.config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + codegen.setHateoas(true); + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, "false"); + + + codegen.setUseOneOfInterfaces(true); + codegen.setLegacyDiscriminatorBehavior(false); + codegen.setUseSpringBoot3(true); + codegen.setModelNameSuffix("DTO"); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false"); + + generator.opts(input).generate(); + + assertFileNotContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/ChildWithMappingADTO.java"), "@JsonTypeName"); + assertFileNotContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/ChildWithMappingBDTO.java"), "@JsonTypeName"); + } + + @Test + public void testDiscriminatorWithoutMappingIssue14731() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + String outputPath = output.getAbsolutePath().replace('\\', '/'); + OpenAPI openAPI = new OpenAPIParser() + .readLocation("src/test/resources/bugs/issue_14731.yaml", null, new ParseOptions()).getOpenAPI(); + + SpringCodegen codegen = new SpringCodegen(); + codegen.setOutputDir(output.getAbsolutePath()); + codegen.additionalProperties().put(CXFServerFeatures.LOAD_TEST_DATA_FROM_FILE, "true"); + codegen.setUseOneOfInterfaces(true); + + ClientOptInput input = new ClientOptInput(); + input.openAPI(openAPI); + input.config(codegen); + + DefaultGenerator generator = new DefaultGenerator(); + codegen.setHateoas(true); + generator.setGeneratorPropertyDefault(CodegenConstants.MODELS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.LEGACY_DISCRIMINATOR_BEHAVIOR, "false"); + + + codegen.setUseOneOfInterfaces(true); + codegen.setLegacyDiscriminatorBehavior(false); + codegen.setUseSpringBoot3(true); + codegen.setModelNameSuffix("DTO"); + + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_TESTS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.MODEL_DOCS, "false"); + generator.setGeneratorPropertyDefault(CodegenConstants.APIS, "true"); + generator.setGeneratorPropertyDefault(CodegenConstants.SUPPORTING_FILES, "false"); + + generator.opts(input).generate(); + + + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/ChildWithoutMappingADTO.java"), "@JsonTypeName"); + assertFileContains(Paths.get(outputPath + "/src/main/java/org/openapitools/model/ChildWithoutMappingBDTO.java"), "@JsonTypeName"); + } + @Test public void testTypeMappings() { final SpringCodegen codegen = new SpringCodegen(); diff --git a/modules/openapi-generator/src/test/resources/bugs/issue_14731.yaml b/modules/openapi-generator/src/test/resources/bugs/issue_14731.yaml new file mode 100644 index 00000000000..7aac956d3e2 --- /dev/null +++ b/modules/openapi-generator/src/test/resources/bugs/issue_14731.yaml @@ -0,0 +1,109 @@ +openapi: '3.0.0' +info: + version: '1.0.0' + title: 'FooService' +paths: + /parentWithMapping: + put: + tags: + - pet + summary: put parent + operationId: putParentWithMapping + requestBody: + description: The updated account definition to save. + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ParentWithMapping' + responses: + '200': + $ref: '#/components/responses/ParentWithMapping' + /parentWithoutMapping: + put: + tags: + - pet + summary: put parent + operationId: putParentWithoutMapping + requestBody: + description: The updated account definition to save. + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/ParentWithoutMapping' + responses: + '200': + $ref: '#/components/responses/ParentWithoutMapping' +components: + schemas: + ParentWithMapping: + type: object + description: Defines an account by name. + properties: + childType: + $ref: '#/components/schemas/ChildType' + required: + - type + discriminator: + propertyName: childType + mapping: + child_a: '#/components/schemas/ChildWithMappingA' + child_b: '#/components/schemas/ChildWithMappingB' + + ChildWithMappingA: + allOf: + - $ref: "#/components/schemas/ParentWithMapping" + - type: object + properties: + nameA: + type: string + ChildWithMappingB: + allOf: + - $ref: "#/components/schemas/ParentWithMapping" + - type: object + properties: + nameB: + type: string + ChildType: + type: string + x-extensible-enum: + - child_a + - child_b + ParentWithoutMapping: + type: object + description: Defines an account by name. + properties: + childType: + $ref: '#/components/schemas/ChildType' + required: + - type + discriminator: + propertyName: childType + ChildWithoutMappingA: + allOf: + - $ref: "#/components/schemas/ParentWithoutMapping" + - type: object + properties: + nameA: + type: string + ChildWithoutMappingB: + allOf: + - $ref: "#/components/schemas/ParentWithoutMapping" + - type: object + properties: + nameB: + type: string + responses: + ParentWithMapping: + description: OK + content: + application/json: + schema: + $ref: '#/components/schemas/ParentWithMapping' + ParentWithoutMapping: + description: The saved account definition. + content: + application/json: + schema: + $ref: '#/components/schemas/ParentWithoutMapping' \ No newline at end of file diff --git a/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/model/AnimalDto.java b/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/model/AnimalDto.java index 87b60c3cdb2..c17b0385407 100644 --- a/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/model/AnimalDto.java +++ b/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/model/AnimalDto.java @@ -34,7 +34,6 @@ import jakarta.annotation.Generated; @JsonSubTypes.Type(value = DogDto.class, name = "Dog") }) -@JsonTypeName("Animal") @Generated(value = "org.openapitools.codegen.languages.SpringCodegen") public class AnimalDto { diff --git a/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/model/CatDto.java b/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/model/CatDto.java index 99cf34ad232..61f8bc958e6 100644 --- a/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/model/CatDto.java +++ b/samples/client/petstore/spring-http-interface/src/main/java/org/openapitools/model/CatDto.java @@ -31,7 +31,6 @@ import jakarta.annotation.Generated; @JsonSubTypes.Type(value = BigCatDto.class, name = "BigCat") }) -@JsonTypeName("Cat") @Generated(value = "org.openapitools.codegen.languages.SpringCodegen") public class CatDto extends AnimalDto { diff --git a/samples/server/petstore/springboot/src/main/java/org/openapitools/model/AnimalDto.java b/samples/server/petstore/springboot/src/main/java/org/openapitools/model/AnimalDto.java index aba7e9e70f5..3d6817c8f8c 100644 --- a/samples/server/petstore/springboot/src/main/java/org/openapitools/model/AnimalDto.java +++ b/samples/server/petstore/springboot/src/main/java/org/openapitools/model/AnimalDto.java @@ -37,7 +37,6 @@ import javax.annotation.Generated; @JsonSubTypes.Type(value = DogDto.class, name = "Dog") }) -@JsonTypeName("Animal") @Generated(value = "org.openapitools.codegen.languages.SpringCodegen") public class AnimalDto { diff --git a/samples/server/petstore/springboot/src/main/java/org/openapitools/model/CatDto.java b/samples/server/petstore/springboot/src/main/java/org/openapitools/model/CatDto.java index ffbd4428513..3d11bd7ba3a 100644 --- a/samples/server/petstore/springboot/src/main/java/org/openapitools/model/CatDto.java +++ b/samples/server/petstore/springboot/src/main/java/org/openapitools/model/CatDto.java @@ -34,7 +34,6 @@ import javax.annotation.Generated; @JsonSubTypes.Type(value = BigCatDto.class, name = "BigCat") }) -@JsonTypeName("Cat") @Generated(value = "org.openapitools.codegen.languages.SpringCodegen") public class CatDto extends AnimalDto {