[java-micronaut] Support Optional for non-required properties (#12144)

The Micronaut generator by default adds the @Nullable annotation to
non-required properties and allows using the Jackson JsonNullable
wrapper but it is not possible to use java.util.Optional as a wrapper
for optional properties.

This change adds support for using the Optional wrapper for non-required
properties.
This commit is contained in:
Auke Schrijnen
2022-04-21 04:53:56 +02:00
committed by GitHub
parent e98c054693
commit a8d4c00662
6 changed files with 37 additions and 4 deletions

View File

@@ -72,6 +72,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|testOutput|Set output folder for models and APIs tests| |${project.build.directory}/generated-test-sources/openapi|
|title|Client service name| |null|
|useBeanValidation|Use BeanValidation API annotations| |true|
|useOptional|Use Optional container for optional parameters| |false|
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|
## SUPPORTED VENDOR EXTENSIONS

View File

@@ -74,6 +74,7 @@ These options may be applied as additional-properties (cli) or configOptions (pl
|title|Client service name| |null|
|useAuth|Whether to import authorization and to annotate controller methods accordingly| |true|
|useBeanValidation|Use BeanValidation API annotations| |true|
|useOptional|Use Optional container for optional parameters| |false|
|withXml|whether to include support for application/xml content type and include XML annotations in the model (works with libraries that provide support for JSON and XML)| |false|
## SUPPORTED VENDOR EXTENSIONS

View File

@@ -3,6 +3,7 @@ package org.openapitools.codegen.languages;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.*;
import org.openapitools.codegen.languages.features.BeanValidationFeatures;
import org.openapitools.codegen.languages.features.OptionalFeatures;
import org.openapitools.codegen.meta.features.DocumentationFeature;
import org.openapitools.codegen.meta.features.SecurityFeature;
import org.openapitools.codegen.model.ModelMap;
@@ -15,7 +16,7 @@ import java.util.stream.Collectors;
import static org.openapitools.codegen.CodegenConstants.INVOKER_PACKAGE;
public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen implements BeanValidationFeatures {
public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen implements BeanValidationFeatures, OptionalFeatures {
public static final String OPT_TITLE = "title";
public static final String OPT_BUILD = "build";
public static final String OPT_BUILD_GRADLE = "gradle";
@@ -34,6 +35,7 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i
protected String title;
protected boolean useBeanValidation;
protected boolean useOptional;
protected String buildTool;
protected String testTool;
protected boolean requiredPropertiesInConstructor = true;
@@ -52,6 +54,7 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i
// Set all the fields
useBeanValidation = true;
useOptional = false;
buildTool = OPT_BUILD_ALL;
testTool = OPT_TEST_JUNIT;
outputFolder = "generated-code/java-micronaut-client";
@@ -95,6 +98,7 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i
cliOptions.add(new CliOption(OPT_TITLE, "Client service name").defaultValue(title));
cliOptions.add(new CliOption(OPT_MICRONAUT_VERSION, "Micronaut version, only >=3.0.0 versions are supported").defaultValue(micronautVersion));
cliOptions.add(CliOption.newBoolean(USE_BEANVALIDATION, "Use BeanValidation API annotations", useBeanValidation));
cliOptions.add(CliOption.newBoolean(USE_OPTIONAL, "Use Optional container for optional parameters", useOptional));
cliOptions.add(CliOption.newBoolean(OPT_REQUIRED_PROPERTIES_IN_CONSTRUCTOR, "Allow only to create models with all the required properties provided in constructor", requiredPropertiesInConstructor));
CliOption buildToolOption = new CliOption(OPT_BUILD, "Specify for which build tool to generate files").defaultValue(buildTool);
@@ -158,6 +162,11 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i
}
writePropertyBack(USE_BEANVALIDATION, useBeanValidation);
if (additionalProperties.containsKey(USE_OPTIONAL)) {
this.setUseOptional(convertPropertyToBoolean(USE_OPTIONAL));
}
writePropertyBack(USE_OPTIONAL, useOptional);
if (additionalProperties.containsKey(OPT_REQUIRED_PROPERTIES_IN_CONSTRUCTOR)) {
this.requiredPropertiesInConstructor = convertPropertyToBoolean(OPT_REQUIRED_PROPERTIES_IN_CONSTRUCTOR);
}
@@ -306,6 +315,11 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i
this.useBeanValidation = useBeanValidation;
}
@Override
public void setUseOptional(boolean useOptional) {
this.useOptional = useOptional;
}
@Override
public String toApiVarName(String name) {
String apiVarName = super.toApiVarName(name);
@@ -319,6 +333,10 @@ public abstract class JavaMicronautAbstractCodegen extends AbstractJavaCodegen i
return useBeanValidation;
}
public boolean isUseOptional() {
return useOptional;
}
@Override
public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List<ModelMap> allModels) {
objs = super.postProcessOperationsWithModels(objs, allModels);

View File

@@ -5,8 +5,8 @@ validate all pojos and enums
nullable & nonnull
}}{{#required}}{{#isNullable}} @Nullable
{{/isNullable}}{{^isNullable}} @NotNull
{{/isNullable}}{{/required}}{{^required}} @Nullable
{{/required}}{{!
{{/isNullable}}{{/required}}{{^required}}{{^useOptional}} @Nullable
{{/useOptional}}{{/required}}{{!
pattern
}}{{#pattern}}{{^isByteArray}} @Pattern(regexp="{{{pattern}}}")
{{/isByteArray}}{{/pattern}}{{!

View File

@@ -7,6 +7,9 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
{{/useReflectionEqualsHashCode}}
import java.util.Objects;
import java.util.Arrays;
{{#useOptional}}
import java.util.Optional;
{{/useOptional}}
{{#imports}}
import {{import}};
{{/imports}}

View File

@@ -186,7 +186,7 @@ Declare the class with extends and implements
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}
{{#jackson}}
{{>common/model/jackson_annotations}}{{/jackson}}{{/vendorExtensions.x-is-jackson-optional-nullable}} public {{{datatypeWithEnum}}} {{getter}}() {
{{>common/model/jackson_annotations}}{{/jackson}}{{/vendorExtensions.x-is-jackson-optional-nullable}} public {{#useOptional}}{{^required}}Optional<{{/required}}{{/useOptional}}{{{datatypeWithEnum}}}{{#useOptional}}{{^required}}>{{/required}}{{/useOptional}} {{getter}}() {
{{#vendorExtensions.x-is-jackson-optional-nullable}}
{{#isReadOnly}}
{{! A readonly attribute doesn't have setter => jackson will set null directly if explicitly returned by API, so make sure we have an empty JsonNullable}} if ({{name}} == null) {
@@ -196,7 +196,17 @@ Declare the class with extends and implements
return {{name}}.orElse(null);
{{/vendorExtensions.x-is-jackson-optional-nullable}}
{{^vendorExtensions.x-is-jackson-optional-nullable}}
{{#useOptional}}
{{#required}}
return {{name}};
{{/required}}
{{^required}}
return Optional.ofNullable({{name}});
{{/required}}
{{/useOptional}}
{{^useOptional}}
return {{name}};
{{/useOptional}}
{{/vendorExtensions.x-is-jackson-optional-nullable}}
}