diff --git a/docs/generators/java-micronaut-client.md b/docs/generators/java-micronaut-client.md index bf0e245caea..e15a6437b5f 100644 --- a/docs/generators/java-micronaut-client.md +++ b/docs/generators/java-micronaut-client.md @@ -18,6 +18,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl | Option | Description | Values | Default | | ------ | ----------- | ------ | ------- | +|additionalClientTypeAnnotations|Additional annotations for client type(class level annotations). List separated by semicolon(;) or new line (Linux or Windows)| |null| |additionalEnumTypeAnnotations|Additional annotations for enum type(class level annotations)| |null| |additionalModelTypeAnnotations|Additional annotations for model type(class level annotations). List separated by semicolon(;) or new line (Linux or Windows)| |null| |additionalOneOfTypeAnnotations|Additional annotations for oneOf interfaces(class level annotations). List separated by semicolon(;) or new line (Linux or Windows)| |null| @@ -70,6 +71,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |scmDeveloperConnection|SCM developer connection in generated pom.xml| |scm:git:git@github.com:openapitools/openapi-generator.git| |scmUrl|SCM URL in generated pom.xml| |https://github.com/openapitools/openapi-generator| |serializableModel|boolean - toggle "implements Serializable" for generated models| |false| +|serializationLibrary|Serialization library for model|
**jackson**
Jackson as serialization library
**micronaut_serde_jackson**
Use micronaut-serialization with Jackson annotations
|jackson| |snapshotVersion|Uses a SNAPSHOT version.|
**true**
Use a SnapShot Version
**false**
Use a Release Version
|null| |sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true| |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| diff --git a/docs/generators/java-micronaut-server.md b/docs/generators/java-micronaut-server.md index d0ccd44dbb1..cce9d87d4e4 100644 --- a/docs/generators/java-micronaut-server.md +++ b/docs/generators/java-micronaut-server.md @@ -72,6 +72,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl |scmDeveloperConnection|SCM developer connection in generated pom.xml| |scm:git:git@github.com:openapitools/openapi-generator.git| |scmUrl|SCM URL in generated pom.xml| |https://github.com/openapitools/openapi-generator| |serializableModel|boolean - toggle "implements Serializable" for generated models| |false| +|serializationLibrary|Serialization library for model|
**jackson**
Jackson as serialization library
**micronaut_serde_jackson**
Use micronaut-serialization with Jackson annotations
|jackson| |snapshotVersion|Uses a SNAPSHOT version.|
**true**
Use a SnapShot Version
**false**
Use a Release Version
|null| |sortModelPropertiesByRequiredFlag|Sort model properties to place required parameters before optional parameters.| |true| |sortParamsByRequiredFlag|Sort method arguments to place required parameters before optional parameters.| |true| diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautAbstractCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautAbstractCodegen.java index e90fcfd5d6c..e169a653e8d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautAbstractCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautAbstractCodegen.java @@ -53,6 +53,7 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i public static final String OPT_GENERATE_SWAGGER_ANNOTATIONS_TRUE = "true"; public static final String OPT_GENERATE_SWAGGER_ANNOTATIONS_FALSE = "false"; public static final String OPT_GENERATE_OPERATION_ONLY_FOR_FIRST_TAG = "generateOperationOnlyForFirstTag"; + public enum SERIALIZATION_LIBRARY_TYPE {jackson, micronaut_serde_jackson} protected final Logger LOGGER = LoggerFactory.getLogger(JavaMicronautAbstractCodegen.class); @@ -69,6 +70,7 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i protected String appName; protected String generateSwaggerAnnotations; protected boolean generateOperationOnlyForFirstTag; + protected String serializationLibrary = SERIALIZATION_LIBRARY_TYPE.jackson.name(); public static final String CONTENT_TYPE_APPLICATION_FORM_URLENCODED = "application/x-www-form-urlencoded"; public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json"; @@ -123,7 +125,6 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i ); // Set additional properties - additionalProperties.put("jackson", "true"); additionalProperties.put("openbrace", "{"); additionalProperties.put("closebrace", "}"); @@ -180,6 +181,14 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i opt.setEnum(valuesEnum); }); + final CliOption serializationLibraryOpt = CliOption.newString(CodegenConstants.SERIALIZATION_LIBRARY, "Serialization library for model"); + serializationLibraryOpt.defaultValue(SERIALIZATION_LIBRARY_TYPE.jackson.name()); + Map serializationLibraryOptions = new HashMap<>(); + serializationLibraryOptions.put(SERIALIZATION_LIBRARY_TYPE.jackson.name(), "Jackson as serialization library"); + serializationLibraryOptions.put(SERIALIZATION_LIBRARY_TYPE.micronaut_serde_jackson.name(), "Use micronaut-serialization with Jackson annotations"); + serializationLibraryOpt.setEnum(serializationLibraryOptions); + cliOptions.add(serializationLibraryOpt); + // Add reserved words String[] reservedWordsArray = { "client", "format", "queryvalue", "queryparam", "pathvariable", "header", "cookie", @@ -305,6 +314,11 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i additionalProperties.put("generateSwagger2Annotations", true); } + if (additionalProperties.containsKey(CodegenConstants.SERIALIZATION_LIBRARY)) { + setSerializationLibrary((String) additionalProperties.get(CodegenConstants.SERIALIZATION_LIBRARY)); + } + additionalProperties.put(this.serializationLibrary, true); + // Add all the supporting files String resourceFolder = projectFolder + "/resources"; supportingFiles.add(new SupportingFile("common/configuration/application.yml.mustache", resourceFolder, "application.yml").doNotOverwrite()); @@ -710,4 +724,16 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i writer.write(fragment.execute().replace('.', '_')); } } + + public void setSerializationLibrary(final String serializationLibrary) { + try { + this.serializationLibrary = JavaMicronautAbstractCodegen.SERIALIZATION_LIBRARY_TYPE.valueOf(serializationLibrary).name(); + } catch (IllegalArgumentException ex) { + StringBuilder sb = new StringBuilder(serializationLibrary + " is an invalid enum property naming option. Please choose from:"); + for (JavaMicronautAbstractCodegen.SERIALIZATION_LIBRARY_TYPE availableSerializationLibrary : JavaMicronautAbstractCodegen.SERIALIZATION_LIBRARY_TYPE.values()) { + sb.append("\n ").append(availableSerializationLibrary.name()); + } + throw new RuntimeException(sb.toString()); + } + } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautClientCodegen.java index 6a530c3af51..9e8d2140fdc 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/JavaMicronautClientCodegen.java @@ -1,5 +1,8 @@ package org.openapitools.codegen.languages; +import java.util.Arrays; +import java.util.List; + import org.openapitools.codegen.CliOption; import org.openapitools.codegen.CodegenType; import org.openapitools.codegen.SupportingFile; @@ -10,10 +13,12 @@ import org.openapitools.codegen.meta.Stability; public class JavaMicronautClientCodegen extends JavaMicronautAbstractCodegen { public static final String OPT_CONFIGURE_AUTH = "configureAuth"; + public static final String ADDITIONAL_CLIENT_TYPE_ANNOTATIONS = "additionalClientTypeAnnotations"; public static final String NAME = "java-micronaut-client"; protected boolean configureAuthorization; + protected List additionalClientTypeAnnotations; public JavaMicronautClientCodegen() { super(); @@ -27,6 +32,7 @@ public class JavaMicronautClientCodegen extends JavaMicronautAbstractCodegen { additionalProperties.put("client", "true"); cliOptions.add(CliOption.newBoolean(OPT_CONFIGURE_AUTH, "Configure all the authorization methods as specified in the file", configureAuthorization)); + cliOptions.add(CliOption.newString(ADDITIONAL_CLIENT_TYPE_ANNOTATIONS, "Additional annotations for client type(class level annotations). List separated by semicolon(;) or new line (Linux or Windows)")); } @Override @@ -75,6 +81,12 @@ public class JavaMicronautClientCodegen extends JavaMicronautAbstractCodegen { supportingFiles.add(new SupportingFile("client/auth/configuration/HttpBasicAuthConfiguration.mustache", authConfigurationFolder, "HttpBasicAuthConfiguration.java")); } + if (additionalProperties.containsKey(ADDITIONAL_CLIENT_TYPE_ANNOTATIONS)) { + String additionalClientAnnotationsList = additionalProperties.get(ADDITIONAL_CLIENT_TYPE_ANNOTATIONS).toString(); + this.setAdditionalClientTypeAnnotations(Arrays.asList(additionalClientAnnotationsList.trim().split("\\s*(;|\\r?\\n)\\s*"))); + additionalProperties.put(ADDITIONAL_CLIENT_TYPE_ANNOTATIONS, additionalClientTypeAnnotations); + } + // Api file apiTemplateFiles.clear(); apiTemplateFiles.put("client/api.mustache", ".java"); @@ -93,4 +105,8 @@ public class JavaMicronautClientCodegen extends JavaMicronautAbstractCodegen { apiDocTemplateFiles.clear(); apiDocTemplateFiles.put("client/doc/api_doc.mustache", ".md"); } + + public void setAdditionalClientTypeAnnotations(final List additionalClientTypeAnnotations) { + this.additionalClientTypeAnnotations = additionalClientTypeAnnotations; + } } diff --git a/modules/openapi-generator/src/main/resources/java-micronaut/client/api.mustache b/modules/openapi-generator/src/main/resources/java-micronaut/client/api.mustache index 22bc78e27b5..30e4b839abc 100644 --- a/modules/openapi-generator/src/main/resources/java-micronaut/client/api.mustache +++ b/modules/openapi-generator/src/main/resources/java-micronaut/client/api.mustache @@ -41,6 +41,9 @@ import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.security.SecurityRequirement; {{/generateSwagger2Annotations}} +{{#additionalClientTypeAnnotations}} + {{{.}}} +{{/additionalClientTypeAnnotations}} {{>common/generatedAnnotation}} @Client("${{openbrace}}{{{applicationName}}}-base-path{{closebrace}}") public interface {{classname}} { diff --git a/modules/openapi-generator/src/main/resources/java-micronaut/common/configuration/gradle/build.gradle.mustache b/modules/openapi-generator/src/main/resources/java-micronaut/common/configuration/gradle/build.gradle.mustache index 5f6fbfd00ef..341fce57ab4 100644 --- a/modules/openapi-generator/src/main/resources/java-micronaut/common/configuration/gradle/build.gradle.mustache +++ b/modules/openapi-generator/src/main/resources/java-micronaut/common/configuration/gradle/build.gradle.mustache @@ -33,6 +33,10 @@ dependencies { {{#useAuth}} annotationProcessor("io.micronaut.security:micronaut-security-annotations") {{/useAuth}} + {{#micronaut_serde_jackson}} + annotationProcessor("io.micronaut.serde:micronaut-serde-processor") + implementation("io.micronaut.serde:micronaut-serde-jackson") + {{/micronaut_serde_jackson}} implementation("io.micronaut:micronaut-http-client") implementation("io.micronaut:micronaut-runtime") implementation("io.micronaut:micronaut-validation") @@ -51,6 +55,15 @@ dependencies { {{/generateSwagger2Annotations}} runtimeOnly("ch.qos.logback:logback-classic") } +{{#micronaut_serde_jackson}} +// TODO Please, check the version of the serde, maybe it must be upgraded. +configurations.all { + resolutionStrategy.dependencySubstitution { + substitute(module("io.micronaut:micronaut-jackson-databind")) + .using(module("io.micronaut.serde:micronaut-serde-jackson:1.3.3")) + } +} +{{/micronaut_serde_jackson}} // TODO Set the main class application { diff --git a/modules/openapi-generator/src/main/resources/java-micronaut/common/configuration/pom.xml.mustache b/modules/openapi-generator/src/main/resources/java-micronaut/common/configuration/pom.xml.mustache index e8da59a73ff..4985d6a6b64 100644 --- a/modules/openapi-generator/src/main/resources/java-micronaut/common/configuration/pom.xml.mustache +++ b/modules/openapi-generator/src/main/resources/java-micronaut/common/configuration/pom.xml.mustache @@ -141,6 +141,24 @@ ${swagger-annotations-version} {{/generateSwagger2Annotations}} + {{#micronaut_serde_jackson}} + + io.micronaut + micronaut-runtime + compile + + + io.micronaut + micronaut-jackson-databind + + + + + io.micronaut.serde + micronaut-serde-jackson + compile + + {{/micronaut_serde_jackson}} @@ -170,6 +188,13 @@ ${micronaut.security.version} {{/useAuth}} + {{#micronaut_serde_jackson}} + + io.micronaut.serde + micronaut-serde-processor + ${micronaut.serialization.version} + + {{/micronaut_serde_jackson}} -Amicronaut.processing.group={{groupId}} diff --git a/modules/openapi-generator/src/main/resources/java-micronaut/common/model/jackson_annotations.mustache b/modules/openapi-generator/src/main/resources/java-micronaut/common/model/jackson_annotations.mustache index 30e167e737c..41afad00289 100644 --- a/modules/openapi-generator/src/main/resources/java-micronaut/common/model/jackson_annotations.mustache +++ b/modules/openapi-generator/src/main/resources/java-micronaut/common/model/jackson_annotations.mustache @@ -18,9 +18,19 @@ {{/isXmlWrapped}} {{/isContainer}} {{/withXml}} - {{#isDateTime}} + {{#jackson}} + {{#isDateTime}} @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "{{{datetimeFormat}}}") - {{/isDateTime}} - {{#isDate}} + {{/isDateTime}} + {{#isDate}} @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "{{{dateFormat}}}") - {{/isDate}} \ No newline at end of file + {{/isDate}} + {{/jackson}} + {{#micronaut_serde_jackson}} + {{#isDateTime}} + @JsonFormat(pattern = "{{{datetimeFormat}}}") + {{/isDateTime}} + {{#isDate}} + @JsonFormat(pattern = "{{{dateFormat}}}") + {{/isDate}} + {{/micronaut_serde_jackson}} \ No newline at end of file diff --git a/modules/openapi-generator/src/main/resources/java-micronaut/common/model/pojo.mustache b/modules/openapi-generator/src/main/resources/java-micronaut/common/model/pojo.mustache index 8292f413b28..b9d60673513 100644 --- a/modules/openapi-generator/src/main/resources/java-micronaut/common/model/pojo.mustache +++ b/modules/openapi-generator/src/main/resources/java-micronaut/common/model/pojo.mustache @@ -9,6 +9,9 @@ @Schema({{#name}}name = "{{name}}", {{/name}}description = "{{{description}}}") {{/generateSwagger2Annotations}} {{/description}} +{{#micronaut_serde_jackson}} +@io.micronaut.serde.annotation.Serdeable +{{/micronaut_serde_jackson}} {{#jackson}} @JsonPropertyOrder({ {{#vars}} @@ -236,8 +239,8 @@ Declare the class with extends and implements {{^isReadOnly}} {{#jackson}} {{^vendorExtensions.x-is-jackson-optional-nullable}} -{{>common/model/jackson_annotations}}{{/vendorExtensions.x-is-jackson-optional-nullable}}{{/jackson}}{{#vendorExtensions.x-setter-extra-annotation}} {{{vendorExtensions.x-setter-extra-annotation}}} -{{/vendorExtensions.x-setter-extra-annotation}} public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { +{{>common/model/jackson_annotations}}{{/vendorExtensions.x-is-jackson-optional-nullable}}{{#vendorExtensions.x-setter-extra-annotation}} {{{vendorExtensions.x-setter-extra-annotation}}} +{{/vendorExtensions.x-setter-extra-annotation}}{{/jackson}} public void {{setter}}({{{datatypeWithEnum}}} {{name}}) { {{#vendorExtensions.x-is-jackson-optional-nullable}} this.{{name}} = JsonNullable.<{{{datatypeWithEnum}}}>of({{name}}); {{/vendorExtensions.x-is-jackson-optional-nullable}} diff --git a/modules/openapi-generator/src/main/resources/java-micronaut/common/model/typeInfoAnnotation.mustache b/modules/openapi-generator/src/main/resources/java-micronaut/common/model/typeInfoAnnotation.mustache index c833321ebfa..42f63ee9ae8 100644 --- a/modules/openapi-generator/src/main/resources/java-micronaut/common/model/typeInfoAnnotation.mustache +++ b/modules/openapi-generator/src/main/resources/java-micronaut/common/model/typeInfoAnnotation.mustache @@ -15,3 +15,20 @@ {{/-last}} {{/discriminator.mappedModels}} {{/jackson}} +{{#micronaut_serde_jackson}} + +@JsonIgnoreProperties( + value = "{{{discriminator.propertyBaseName}}}", // ignore manually set {{{discriminator.propertyBaseName}}}, it will be automatically generated by Jackson during serialization + allowSetters = true // allows the {{{discriminator.propertyBaseName}}} to be set during deserialization +) +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "{{{discriminator.propertyBaseName}}}") +{{#discriminator.mappedModels}} +{{#-first}} +@JsonSubTypes({ +{{/-first}} + @JsonSubTypes.Type(value = {{modelName}}.class, name = "{{^vendorExtensions.x-discriminator-value}}{{mappingName}}{{/vendorExtensions.x-discriminator-value}}{{#vendorExtensions.x-discriminator-value}}{{{vendorExtensions.x-discriminator-value}}}{{/vendorExtensions.x-discriminator-value}}"), +{{#-last}} +}) +{{/-last}} +{{/discriminator.mappedModels}} +{{/micronaut_serde_jackson}} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/micronaut/JavaMicronautClientCodegenSerializationLibraryTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/micronaut/JavaMicronautClientCodegenSerializationLibraryTest.java new file mode 100644 index 00000000000..77569fcb5ee --- /dev/null +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/micronaut/JavaMicronautClientCodegenSerializationLibraryTest.java @@ -0,0 +1,53 @@ +package org.openapitools.codegen.java.micronaut; + +import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.languages.JavaMicronautAbstractCodegen; +import org.openapitools.codegen.languages.JavaMicronautClientCodegen; +import org.testng.annotations.Test; + +public class JavaMicronautClientCodegenSerializationLibraryTest extends AbstractMicronautCodegenTest { + + @Test + public void testSerializationLibraryJackson() { + JavaMicronautClientCodegen codegen = new JavaMicronautClientCodegen(); + codegen.additionalProperties().put(CodegenConstants.SERIALIZATION_LIBRARY, JavaMicronautAbstractCodegen.SERIALIZATION_LIBRARY_TYPE.jackson.name()); + String outputPath = generateFiles(codegen, PETSTORE_PATH, + CodegenConstants.MODELS); + + // Model does not contain micronaut serde annotation + String micronautSerDeAnnotation = "@io.micronaut.serde.annotation.Serdeable"; + String modelPath = outputPath + "src/main/java/org/openapitools/model/"; + assertFileNotContains(modelPath + "Pet.java", micronautSerDeAnnotation); + assertFileNotContains(modelPath + "User.java", micronautSerDeAnnotation); + assertFileNotContains(modelPath + "Order.java", micronautSerDeAnnotation); + assertFileNotContains(modelPath + "Tag.java", micronautSerDeAnnotation); + assertFileNotContains(modelPath + "Category.java", micronautSerDeAnnotation); + + //JsonFormat with jackson must be with shape attribute + assertFileContains(modelPath + "Order.java", "@JsonFormat(shape = JsonFormat.Shape.STRING"); + } + + /** + * Checks micronaut-serde-jackson limitation. + * @see + */ + @Test + public void testSerializationLibraryMicronautSerdeJackson() { + JavaMicronautClientCodegen codegen = new JavaMicronautClientCodegen(); + codegen.additionalProperties().put(CodegenConstants.SERIALIZATION_LIBRARY, JavaMicronautAbstractCodegen.SERIALIZATION_LIBRARY_TYPE.micronaut_serde_jackson.name()); + String outputPath = generateFiles(codegen, PETSTORE_PATH, + CodegenConstants.MODELS); + + // Model contains micronaut serde annotation + String micronautSerDeAnnotation = "@io.micronaut.serde.annotation.Serdeable"; + String modelPath = outputPath + "src/main/java/org/openapitools/model/"; + assertFileContains(modelPath + "Pet.java", micronautSerDeAnnotation); + assertFileContains(modelPath + "User.java", micronautSerDeAnnotation); + assertFileContains(modelPath + "Order.java", micronautSerDeAnnotation); + assertFileContains(modelPath + "Tag.java", micronautSerDeAnnotation); + assertFileContains(modelPath + "Category.java", micronautSerDeAnnotation); + + //JsonFormat with micronaut-serde-jackson must be without shape attribute + assertFileNotContains(modelPath + "Order.java", "@JsonFormat(shape = JsonFormat.Shape.STRING"); + } +} diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/micronaut/MicronautClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/micronaut/MicronautClientCodegenTest.java index 2a19418c9a4..af612bd47ca 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/micronaut/MicronautClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/micronaut/MicronautClientCodegenTest.java @@ -239,4 +239,16 @@ public class MicronautClientCodegenTest extends AbstractMicronautCodegenTest { String resourcesPath = outputPath + "src/main/resources/"; assertFileContains(resourcesPath + "application.yml", "OAuth_2_0_Client_Credentials:"); } + + @Test + public void testAdditionalClientTypeAnnotations() { + JavaMicronautClientCodegen codegen = new JavaMicronautClientCodegen(); + codegen.additionalProperties().put(JavaMicronautClientCodegen.ADDITIONAL_CLIENT_TYPE_ANNOTATIONS, "MyAdditionalAnnotation1(1,${param1});MyAdditionalAnnotation2(2,${param2});"); + String outputPath = generateFiles(codegen, PETSTORE_PATH, + CodegenConstants.APIS); + + // Micronaut declarative http client should contain custom added annotations + assertFileContains(outputPath + "/src/main/java/org/openapitools/api/PetApi.java", "MyAdditionalAnnotation1(1,${param1})"); + assertFileContains(outputPath + "/src/main/java/org/openapitools/api/PetApi.java", "MyAdditionalAnnotation2(2,${param2})"); + } }