From 9c2eff94ae9111778bc2677af5a2a223641ce966 Mon Sep 17 00:00:00 2001 From: osztosa Date: Sun, 3 Dec 2023 17:02:53 +0100 Subject: [PATCH 1/6] lineSeparator fix --- .../java/JavaPolymorphicAnnotationCodegenTest.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/JavaPolymorphicAnnotationCodegenTest.java b/src/test/java/io/swagger/codegen/v3/generators/java/JavaPolymorphicAnnotationCodegenTest.java index d3ad04763c..c749d39662 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/JavaPolymorphicAnnotationCodegenTest.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/JavaPolymorphicAnnotationCodegenTest.java @@ -31,10 +31,10 @@ public void testParameterOrders() throws Exception { final String content = FileUtils.readFileToString(petControllerFile); Assert.assertTrue(content.contains( - "@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = \"type\", visible = true )\n" + - "@JsonSubTypes({\n" + - " @JsonSubTypes.Type(value = Error.class, name = \"Error\"),\n" + - " @JsonSubTypes.Type(value = Success.class, name = \"Success\"),\n" + + "@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = \"type\", visible = true )" + System.lineSeparator() + + "@JsonSubTypes({" + System.lineSeparator() + + " @JsonSubTypes.Type(value = Error.class, name = \"Error\")," + System.lineSeparator() + + " @JsonSubTypes.Type(value = Success.class, name = \"Success\")," + System.lineSeparator() + "})")); this.folder.delete(); From 989049b75addd886a9c8532e1b6138342dfb9140 Mon Sep 17 00:00:00 2001 From: osztosa Date: Sun, 3 Dec 2023 17:06:22 +0100 Subject: [PATCH 2/6] Interface with custom discriminator test --- .../v3/generators/GeneratorRunner.java | 16 ++- .../java/GeneratorResultTestJava.java | 54 +++++++- .../sample_interface_with_discriminator.json | 118 ++++++++++++++++++ 3 files changed, 183 insertions(+), 5 deletions(-) create mode 100644 src/test/resources/3_0_0/sample_interface_with_discriminator.json diff --git a/src/test/java/io/swagger/codegen/v3/generators/GeneratorRunner.java b/src/test/java/io/swagger/codegen/v3/generators/GeneratorRunner.java index 73b15b0d63..0385fbb4fe 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/GeneratorRunner.java +++ b/src/test/java/io/swagger/codegen/v3/generators/GeneratorRunner.java @@ -13,6 +13,8 @@ import java.io.InputStream; import java.nio.file.Files; import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; /** * @@ -28,7 +30,8 @@ public static List runGenerator( boolean v2Spec, boolean yaml, boolean flattenInlineComposedSchema, - String outFolder + String outFolder, + Consumer optionsCustomizer ) throws Exception { String path = outFolder; @@ -36,6 +39,13 @@ public static List runGenerator( path = getTmpFolder().getAbsolutePath(); } GenerationRequest request = new GenerationRequest(); + + Options option = new Options() + .flattenInlineComposedSchema(flattenInlineComposedSchema) + .outputDir(path); + + optionsCustomizer.accept(option); + request .codegenVersion(codegenVersion) // use V2 to target Swagger/OpenAPI 2.x Codegen version .type(GenerationRequest.Type.CLIENT) @@ -44,9 +54,7 @@ public static List runGenerator( yaml, // YAML file, use false for JSON v2Spec)) // OpenAPI 3.x - use true for Swagger/OpenAPI 2.x definitions .options( - new Options() - .flattenInlineComposedSchema(flattenInlineComposedSchema) - .outputDir(path) + option ); List files = new GeneratorService().generationRequest(request).generate(); diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java index 58509df237..7e5d38d22c 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java @@ -6,7 +6,11 @@ import org.testng.annotations.Test; import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; public class GeneratorResultTestJava { @@ -29,11 +33,59 @@ public void testJavaGenerator_OneOf() throws Exception { v2Spec, yaml, flattenInlineComposedSchema, - outFolder); + outFolder, options -> {}); Assert.assertFalse(files.isEmpty()); for (File f: files) { // TODO test stuff } } + + @Test + public void interfaceWithCustomDiscriminator() throws Exception { + + String name = "java"; + String specPath = "3_0_0/sample_interface_with_discriminator.json"; + GenerationRequest.CodegenVersion codegenVersion = GenerationRequest.CodegenVersion.V3; + boolean v2Spec = false; // 3.0 spec + boolean yaml = false; + boolean flattenInlineComposedSchema = true; + String outFolder = null; // temporary folder + + + List files = GeneratorRunner.runGenerator( + name, + specPath, + codegenVersion, + v2Spec, + yaml, + flattenInlineComposedSchema, + outFolder, + options -> options.setLibrary("resttemplate")); + + + + File interfaceFile = files.stream().filter(f -> f.getName().equals("Item.java")).findAny().orElseThrow(() -> new RuntimeException("No interface generated")); + + String interfaceContent = new String(Files.readAllBytes(Paths.get(interfaceFile.toURI()))); + + Pattern typeInfoPattern = Pattern.compile( "(.*)(@JsonTypeInfo\\()(.*)(}\\))(.*)", Pattern.DOTALL); + + Matcher matcher = typeInfoPattern.matcher(interfaceContent); + + Assert.assertTrue(matcher.matches(), "No JsonTypeInfo generated into the interface file"); + + String generatedTypeinfoLines = matcher.group(2)+matcher.group(3)+matcher.group(4); + + Assert.assertEquals( generatedTypeinfoLines,"@JsonTypeInfo(\n" + + " use = JsonTypeInfo.Id.NAME,\n" + + " include = JsonTypeInfo.As.PROPERTY,\n" + + " property = \"aCustomProperty\")\n" + + "@JsonSubTypes({\n" + + " @JsonSubTypes.Type(value = ClassA.class, name = \"typeA\"),\n" + + " @JsonSubTypes.Type(value = ClassB.class, name = \"typeB\"),\n" + + " @JsonSubTypes.Type(value = ClassC.class, name = \"typeC\")\n" + + "})", "Wrong json subtypes generated"); + + } } diff --git a/src/test/resources/3_0_0/sample_interface_with_discriminator.json b/src/test/resources/3_0_0/sample_interface_with_discriminator.json new file mode 100644 index 0000000000..0ebc9df6cf --- /dev/null +++ b/src/test/resources/3_0_0/sample_interface_with_discriminator.json @@ -0,0 +1,118 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Title", + "description": "Title", + "version": "1.0.0" + }, + "paths": { + "/sampleObjectResponse": { + "get": { + "tags": [ + "Sample" + ], + "responses": { + "200": { + "description": "Returns requested data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/sampleResponse" + } + } + } + } + + } + } + + } + }, + "components": { + "schemas": { + "sampleResponse": { + "type": "array", + "items": { + "$ref": "#/components/schemas/item" + } + }, + "item": { + "discriminator": { + "propertyName": "aCustomProperty", + "mapping": { + "typeA": "#/components/schemas/classA", + "typeB": "#/components/schemas/classB", + "typeC": "#/components/schemas/classC" + } + }, + "oneOf": [ + { + "$ref": "#/components/schemas/classA" + }, + { + "$ref": "#/components/schemas/classB" + }, + { + "$ref": "#/components/schemas/classC" + } + ] + }, + "classA": { + "type": "object", + "properties": { + "aaa": { + "type": "string" + } + }, + "allOf": [ + { + "$ref": "#/components/schemas/baseClass" + } + ] + }, + "classB": { + "type": "object", + "properties": { + "bbb": { + "type": "string" + } + }, + "allOf": [ + { + "$ref": "#/components/schemas/baseClass" + } + ] + }, + "classC": { + "type": "object", + "properties": { + "ccc": { + "type": "string" + } + }, + "allOf": [ + { + "$ref": "#/components/schemas/baseClass" + } + ] + }, + "baseClass": { + + "properties": { + "id": { + "type": "integer" + }, + "name": { + "type": "string" + } + } + } + } + }, + "tags": [ + { + "name": "Sample", + "description": "Sample" + } + ] +} From 313cf27e1c82af46de74e3f4a57cc79dd85a6af8 Mon Sep 17 00:00:00 2001 From: osztosa Date: Sun, 3 Dec 2023 17:41:22 +0100 Subject: [PATCH 3/6] java interface discriminator --- .../v3/generators/DefaultCodegenConfig.java | 94 +++++++------------ .../codegen/v3/generators/SchemaHandler.java | 4 +- .../handlebars/Java/interface.mustache | 4 +- .../java/GeneratorResultTestJava.java | 29 +++--- 4 files changed, 54 insertions(+), 77 deletions(-) diff --git a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java index 144b70327d..6896d74b81 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java +++ b/src/main/java/io/swagger/codegen/v3/generators/DefaultCodegenConfig.java @@ -3,30 +3,9 @@ import com.fasterxml.jackson.databind.JsonNode; import com.github.jknack.handlebars.Handlebars; import com.samskivert.mustache.Mustache; -import io.swagger.codegen.v3.CliOption; -import io.swagger.codegen.v3.CodegenArgument; -import io.swagger.codegen.v3.CodegenConfig; -import io.swagger.codegen.v3.CodegenConstants; -import io.swagger.codegen.v3.CodegenContent; -import io.swagger.codegen.v3.CodegenModel; -import io.swagger.codegen.v3.CodegenModelFactory; -import io.swagger.codegen.v3.CodegenModelType; -import io.swagger.codegen.v3.CodegenOperation; -import io.swagger.codegen.v3.CodegenParameter; -import io.swagger.codegen.v3.CodegenProperty; -import io.swagger.codegen.v3.CodegenResponse; -import io.swagger.codegen.v3.CodegenSecurity; -import io.swagger.codegen.v3.ISchemaHandler; -import io.swagger.codegen.v3.SupportingFile; +import io.swagger.codegen.v3.*; import io.swagger.codegen.v3.generators.examples.ExampleGenerator; -import io.swagger.codegen.v3.generators.handlebars.BaseItemsHelper; -import io.swagger.codegen.v3.generators.handlebars.BracesHelper; -import io.swagger.codegen.v3.generators.handlebars.HasHelper; -import io.swagger.codegen.v3.generators.handlebars.HasNotHelper; -import io.swagger.codegen.v3.generators.handlebars.IsHelper; -import io.swagger.codegen.v3.generators.handlebars.IsNotHelper; -import io.swagger.codegen.v3.generators.handlebars.NotEmptyHelper; -import io.swagger.codegen.v3.generators.handlebars.StringUtilHelper; +import io.swagger.codegen.v3.generators.handlebars.*; import io.swagger.codegen.v3.generators.util.OpenAPIUtil; import io.swagger.codegen.v3.templates.HandlebarTemplateEngine; import io.swagger.codegen.v3.templates.MustacheTemplateEngine; @@ -38,30 +17,8 @@ import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.examples.Example; import io.swagger.v3.oas.models.headers.Header; -import io.swagger.v3.oas.models.media.ArraySchema; -import io.swagger.v3.oas.models.media.BinarySchema; -import io.swagger.v3.oas.models.media.BooleanSchema; -import io.swagger.v3.oas.models.media.ByteArraySchema; -import io.swagger.v3.oas.models.media.ComposedSchema; -import io.swagger.v3.oas.models.media.Content; -import io.swagger.v3.oas.models.media.DateSchema; -import io.swagger.v3.oas.models.media.DateTimeSchema; -import io.swagger.v3.oas.models.media.EmailSchema; -import io.swagger.v3.oas.models.media.FileSchema; -import io.swagger.v3.oas.models.media.IntegerSchema; -import io.swagger.v3.oas.models.media.MapSchema; -import io.swagger.v3.oas.models.media.MediaType; -import io.swagger.v3.oas.models.media.NumberSchema; -import io.swagger.v3.oas.models.media.ObjectSchema; -import io.swagger.v3.oas.models.media.Schema; -import io.swagger.v3.oas.models.media.StringSchema; -import io.swagger.v3.oas.models.media.UUIDSchema; -import io.swagger.v3.oas.models.parameters.CookieParameter; -import io.swagger.v3.oas.models.parameters.HeaderParameter; -import io.swagger.v3.oas.models.parameters.Parameter; -import io.swagger.v3.oas.models.parameters.PathParameter; -import io.swagger.v3.oas.models.parameters.QueryParameter; -import io.swagger.v3.oas.models.parameters.RequestBody; +import io.swagger.v3.oas.models.media.*; +import io.swagger.v3.oas.models.parameters.*; import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; import io.swagger.v3.oas.models.security.OAuthFlow; @@ -99,16 +56,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -import static io.swagger.codegen.v3.CodegenConstants.HAS_ONLY_READ_ONLY_EXT_NAME; -import static io.swagger.codegen.v3.CodegenConstants.HAS_OPTIONAL_EXT_NAME; -import static io.swagger.codegen.v3.CodegenConstants.HAS_REQUIRED_EXT_NAME; -import static io.swagger.codegen.v3.CodegenConstants.IS_ARRAY_MODEL_EXT_NAME; -import static io.swagger.codegen.v3.CodegenConstants.IS_CONTAINER_EXT_NAME; -import static io.swagger.codegen.v3.CodegenConstants.IS_ENUM_EXT_NAME; -import static io.swagger.codegen.v3.generators.CodegenHelper.getDefaultIncludes; -import static io.swagger.codegen.v3.generators.CodegenHelper.getImportMappings; -import static io.swagger.codegen.v3.generators.CodegenHelper.getTypeMappings; -import static io.swagger.codegen.v3.generators.CodegenHelper.initalizeSpecialCharacterMapping; +import static io.swagger.codegen.v3.CodegenConstants.*; +import static io.swagger.codegen.v3.generators.CodegenHelper.*; import static io.swagger.codegen.v3.generators.handlebars.ExtensionHelper.getBooleanValue; public abstract class DefaultCodegenConfig implements CodegenConfig { @@ -1345,9 +1294,7 @@ public CodegenModel fromModel(String name, Schema schema, Map al codegenModel.getVendorExtensions().put(CodegenConstants.IS_ALIAS_EXT_NAME, typeAliases.containsKey(name)); codegenModel.discriminator = schema.getDiscriminator(); - if (codegenModel.discriminator != null && codegenModel.discriminator.getPropertyName() != null) { - codegenModel.discriminator.setPropertyName(toVarName(codegenModel.discriminator.getPropertyName())); - } + if (schema.getXml() != null) { codegenModel.xmlPrefix = schema.getXml().getPrefix(); @@ -1398,6 +1345,33 @@ else if (schema instanceof ComposedSchema) { } } } + + if (codegenModel.discriminator != null && codegenModel.discriminator.getPropertyName() != null) { + codegenModel.discriminator.setPropertyName(toVarName(codegenModel.discriminator.getPropertyName())); + Map classnameKeys = new HashMap<>(); + + if (composed.getOneOf()!=null) { + composed.getOneOf().forEach( s -> { + + codegenModel.discriminator.getMapping().keySet().stream().filter( key -> codegenModel.discriminator.getMapping().get(key).equals(s.get$ref())) + .forEach(key -> { + String mappingValue = codegenModel.discriminator.getMapping().get(key); + if (classnameKeys.containsKey(codegenModel.classname)) { + throw new IllegalArgumentException("Duplicate shema name in discriminator mapping"); + } + classnameKeys.put(toModelName(mappingValue.replace("#/components/schemas/", "")),key); + }); + + }); + + codegenModel.discriminator.getMapping().putAll(classnameKeys); + + } + + + } + + } else { allProperties = null; allRequired = null; diff --git a/src/main/java/io/swagger/codegen/v3/generators/SchemaHandler.java b/src/main/java/io/swagger/codegen/v3/generators/SchemaHandler.java index 09f0e13cd9..315f8151cd 100644 --- a/src/main/java/io/swagger/codegen/v3/generators/SchemaHandler.java +++ b/src/main/java/io/swagger/codegen/v3/generators/SchemaHandler.java @@ -199,9 +199,7 @@ protected void addInterfaces(List schemas, CodegenModel codegenModel, Ma codegenModel.addSubType(model); } - if (codegenModel.getVendorExtensions() == null || codegenModel.getVendorExtensions().containsKey("x-discriminator-type")) { - continue; - } + if (codegenModel.getDiscriminator() != null && StringUtils.isNotBlank(codegenModel.getDiscriminator().getPropertyName())) { Optional optionalProperty = model.vars.stream() .filter(codegenProperty -> codegenProperty.baseName.equals(codegenModel.getDiscriminator().getPropertyName())).findFirst(); diff --git a/src/main/resources/handlebars/Java/interface.mustache b/src/main/resources/handlebars/Java/interface.mustache index 0d08bbe545..d3d7202e24 100644 --- a/src/main/resources/handlebars/Java/interface.mustache +++ b/src/main/resources/handlebars/Java/interface.mustache @@ -9,10 +9,10 @@ import com.fasterxml.jackson.annotation.JsonTypeInfo; @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, - property = "type") + property = "{{discriminator.propertyName}}") @JsonSubTypes({ {{#subTypes}} - @JsonSubTypes.Type(value = {{classname}}.class, name = "{{classname}}"){{^@last}},{{/@last}} + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{subtypeName}}"){{^@last}},{{/@last}} {{/subTypes}} }) {{/jackson}} diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java index 7e5d38d22c..a6f526b11c 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java @@ -1,7 +1,9 @@ package io.swagger.codegen.v3.generators.java; +import com.fasterxml.jackson.annotation.JsonSubTypes; import io.swagger.codegen.v3.generators.GeneratorRunner; import io.swagger.codegen.v3.service.GenerationRequest; +import org.apache.commons.io.FileUtils; import org.testng.Assert; import org.testng.annotations.Test; @@ -52,6 +54,8 @@ public void interfaceWithCustomDiscriminator() throws Exception { boolean flattenInlineComposedSchema = true; String outFolder = null; // temporary folder + File tmpFolder = GeneratorRunner.getTmpFolder(); + Assert.assertNotNull(tmpFolder); List files = GeneratorRunner.runGenerator( name, @@ -60,11 +64,10 @@ public void interfaceWithCustomDiscriminator() throws Exception { v2Spec, yaml, flattenInlineComposedSchema, - outFolder, + tmpFolder.getAbsolutePath(), options -> options.setLibrary("resttemplate")); - File interfaceFile = files.stream().filter(f -> f.getName().equals("Item.java")).findAny().orElseThrow(() -> new RuntimeException("No interface generated")); String interfaceContent = new String(Files.readAllBytes(Paths.get(interfaceFile.toURI()))); @@ -73,19 +76,21 @@ public void interfaceWithCustomDiscriminator() throws Exception { Matcher matcher = typeInfoPattern.matcher(interfaceContent); - Assert.assertTrue(matcher.matches(), "No JsonTypeInfo generated into the interface file"); + Assert.assertTrue(matcher.matches(), + "No JsonTypeInfo generated into the interface file"); - String generatedTypeinfoLines = matcher.group(2)+matcher.group(3)+matcher.group(4); + String generatedTypeInfoLines = matcher.group(2)+matcher.group(3)+matcher.group(4); - Assert.assertEquals( generatedTypeinfoLines,"@JsonTypeInfo(\n" + - " use = JsonTypeInfo.Id.NAME,\n" + - " include = JsonTypeInfo.As.PROPERTY,\n" + - " property = \"aCustomProperty\")\n" + - "@JsonSubTypes({\n" + - " @JsonSubTypes.Type(value = ClassA.class, name = \"typeA\"),\n" + - " @JsonSubTypes.Type(value = ClassB.class, name = \"typeB\"),\n" + - " @JsonSubTypes.Type(value = ClassC.class, name = \"typeC\")\n" + + Assert.assertEquals( generatedTypeInfoLines, "@JsonTypeInfo(" + System.lineSeparator() + + " use = JsonTypeInfo.Id.NAME," + System.lineSeparator() + + " include = JsonTypeInfo.As.PROPERTY," + System.lineSeparator() + + " property = \"aCustomProperty\")" + System.lineSeparator() + + "@JsonSubTypes({" + System.lineSeparator() + + " @JsonSubTypes.Type(value = ClassA.class, name = \"typeA\")," + System.lineSeparator() + + " @JsonSubTypes.Type(value = ClassB.class, name = \"typeB\")," + System.lineSeparator() + + " @JsonSubTypes.Type(value = ClassC.class, name = \"typeC\")" + System.lineSeparator() + "})", "Wrong json subtypes generated"); + FileUtils.deleteDirectory(new File(tmpFolder.getAbsolutePath())); } } From 7609ec0ced7b6528cdcdc3b1502e3145db907f8b Mon Sep 17 00:00:00 2001 From: osztosa Date: Sat, 9 Dec 2023 21:14:43 +0100 Subject: [PATCH 4/6] fix issue 804 - java discriminator mapping --- .../Java/typeInfoAnnotation.mustache | 2 +- .../java/GeneratorResultTestJava.java | 47 +++++++++++++++++ .../3_0_0/javaDiscriminatorExample.yaml | 52 +++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/test/resources/3_0_0/javaDiscriminatorExample.yaml diff --git a/src/main/resources/handlebars/Java/typeInfoAnnotation.mustache b/src/main/resources/handlebars/Java/typeInfoAnnotation.mustache index f2a2e1c88f..b6bb41acee 100644 --- a/src/main/resources/handlebars/Java/typeInfoAnnotation.mustache +++ b/src/main/resources/handlebars/Java/typeInfoAnnotation.mustache @@ -2,6 +2,6 @@ @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{discriminator.propertyName}}", visible = true ) @JsonSubTypes({ {{#children}} - @JsonSubTypes.Type(value = {{classname}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{name}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"), + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{subtypeName}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"), {{/children}} }){{/jackson}} diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java index a6f526b11c..1d479156b9 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java @@ -93,4 +93,51 @@ public void interfaceWithCustomDiscriminator() throws Exception { FileUtils.deleteDirectory(new File(tmpFolder.getAbsolutePath())); } + + @Test + public void javaCustomDiscriminator() throws Exception { + + String name = "java"; + String specPath = "3_0_0/javaDiscriminatorExample.yaml"; + GenerationRequest.CodegenVersion codegenVersion = GenerationRequest.CodegenVersion.V3; + boolean v2Spec = false; // 3.0 spec + boolean yaml = true; + boolean flattenInlineComposedSchema = true; + String outFolder = null; // temporary folder + + File tmpFolder = GeneratorRunner.getTmpFolder(); + Assert.assertNotNull(tmpFolder); + + List files = GeneratorRunner.runGenerator( + name, + specPath, + codegenVersion, + v2Spec, + yaml, + flattenInlineComposedSchema, + tmpFolder.getAbsolutePath(), + options -> options.setLibrary("resttemplate")); + + + File interfaceFile = files.stream().filter(f -> f.getName().equals("ResultForSubTypeDTO.java")).findAny().orElseThrow(() -> new RuntimeException("No class generated")); + + String interfaceContent = new String(Files.readAllBytes(Paths.get(interfaceFile.toURI()))); + + Pattern typeInfoPattern = Pattern.compile( "(.*)(@JsonTypeInfo\\()(.*)(}\\))(.*)", Pattern.DOTALL); + + Matcher matcher = typeInfoPattern.matcher(interfaceContent); + + Assert.assertTrue(matcher.matches(), + "No JsonTypeInfo generated into the interface file"); + + String generatedTypeInfoLines = matcher.group(2)+matcher.group(3)+matcher.group(4); + + Assert.assertEquals( generatedTypeInfoLines, "@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = \"type\", visible = true )" + System.lineSeparator() + + "@JsonSubTypes({" + System.lineSeparator() + + " @JsonSubTypes.Type(value = SubTypeBResultDTO.class, name = \"WeirdlyNamedSubTypeB\")," + System.lineSeparator() + + " @JsonSubTypes.Type(value = SubTypeAResultDTO.class, name = \"SubTypeA\")," + System.lineSeparator() + + "})"); + + FileUtils.deleteDirectory(new File(tmpFolder.getAbsolutePath())); + } } diff --git a/src/test/resources/3_0_0/javaDiscriminatorExample.yaml b/src/test/resources/3_0_0/javaDiscriminatorExample.yaml new file mode 100644 index 0000000000..39a67601b9 --- /dev/null +++ b/src/test/resources/3_0_0/javaDiscriminatorExample.yaml @@ -0,0 +1,52 @@ +openapi: '3.0.3' +info: + title: 'Discriminator Problem API' + version: '1.0.0' + +components: + schemas: + SomeTypeDTO: + type: string + enum: + - SubTypeA + - WeirdlyNamedSubTypeB + + ResultForSubTypeDTO: + type: object + properties: + type: + type: string + oneOf: + - $ref: '#/components/schemas/SubTypeAResultDTO' + - $ref: '#/components/schemas/SubTypeBResultDTO' + required: + - type + discriminator: + propertyName: type + mapping: + SubTypeA: '#/components/schemas/SubTypeAResultDTO' + WeirdlyNamedSubTypeB: '#/components/schemas/SubTypeBResultDTO' + + SubTypeAResultDTO: + allOf: + - $ref: '#/components/schemas/ResultForSubTypeDTO' + type: object + properties: + some_attribute: + type: string + + SubTypeBResultDTO: + allOf: + - $ref: '#/components/schemas/ResultForSubTypeDTO' + type: object + properties: + another_attribute: + type: string + +paths: + /repro: + get: + operationId: 'getRepo' + responses: + 204: + description: OK \ No newline at end of file From 12f35aebf28e3affbb8ed0ea1eb424d226695404 Mon Sep 17 00:00:00 2001 From: Hugo Mercado Date: Thu, 15 Feb 2024 12:22:45 -0500 Subject: [PATCH 5/6] remove discriminator mapping call from template --- .../resources/handlebars/Java/typeInfoAnnotation.mustache | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/main/resources/handlebars/Java/typeInfoAnnotation.mustache b/src/main/resources/handlebars/Java/typeInfoAnnotation.mustache index 2216ea419f..a6a3a6a71a 100644 --- a/src/main/resources/handlebars/Java/typeInfoAnnotation.mustache +++ b/src/main/resources/handlebars/Java/typeInfoAnnotation.mustache @@ -1,14 +1,8 @@ {{#jackson}} @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{discriminator.propertyName}}", visible = true ) @JsonSubTypes({ -{{#if discriminator.mapping}} -{{#each discriminator.mapping}} - @JsonSubTypes.Type(value = {{this}}.class, name = "{{@key}}"), -{{/each}} -{{else}} {{#children}} - @JsonSubTypes.Type(value = {{classname}}.class, name = "{{name}}"), + @JsonSubTypes.Type(value = {{classname}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{subtypeName}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"), {{/children}} -{{/if}} }) {{/jackson}} \ No newline at end of file From 3029c17b8c5517a49b0f6ca3f0de9703dd0f4f9e Mon Sep 17 00:00:00 2001 From: Hugo Mercado Date: Thu, 15 Feb 2024 12:46:22 -0500 Subject: [PATCH 6/6] removed no required tabs --- .../codegen/v3/generators/java/GeneratorResultTestJava.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java index 1d479156b9..41cd2587e6 100644 --- a/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java +++ b/src/test/java/io/swagger/codegen/v3/generators/java/GeneratorResultTestJava.java @@ -72,7 +72,7 @@ public void interfaceWithCustomDiscriminator() throws Exception { String interfaceContent = new String(Files.readAllBytes(Paths.get(interfaceFile.toURI()))); - Pattern typeInfoPattern = Pattern.compile( "(.*)(@JsonTypeInfo\\()(.*)(}\\))(.*)", Pattern.DOTALL); + Pattern typeInfoPattern = Pattern.compile("(.*)(@JsonTypeInfo\\()(.*)(}\\))(.*)", Pattern.DOTALL); Matcher matcher = typeInfoPattern.matcher(interfaceContent); @@ -123,7 +123,7 @@ public void javaCustomDiscriminator() throws Exception { String interfaceContent = new String(Files.readAllBytes(Paths.get(interfaceFile.toURI()))); - Pattern typeInfoPattern = Pattern.compile( "(.*)(@JsonTypeInfo\\()(.*)(}\\))(.*)", Pattern.DOTALL); + Pattern typeInfoPattern = Pattern.compile("(.*)(@JsonTypeInfo\\()(.*)(}\\))(.*)", Pattern.DOTALL); Matcher matcher = typeInfoPattern.matcher(interfaceContent);