Skip to content

Commit

Permalink
Generator improvements (#1088)
Browse files Browse the repository at this point in the history
  • Loading branch information
andriy-dmytruk authored Jun 30, 2023
1 parent 4ad0c31 commit 1fce141
Show file tree
Hide file tree
Showing 17 changed files with 863 additions and 517 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import com.samskivert.mustache.Template;
import io.swagger.v3.oas.models.Operation;
import io.swagger.v3.oas.models.media.Schema;
import io.swagger.v3.oas.models.parameters.Parameter;
import io.swagger.v3.oas.models.servers.Server;
import org.apache.commons.lang3.StringUtils;
import org.openapitools.codegen.CliOption;
Expand Down Expand Up @@ -57,6 +58,11 @@

import static org.openapitools.codegen.CodegenConstants.INVOKER_PACKAGE;

/**
* Base generator for Micronaut.
*
* @param <T> The generator options builder.
*/
@SuppressWarnings("checkstyle:DesignForExtension")
public abstract class AbstractMicronautJavaCodegen<T extends GeneratorOptionsBuilder> extends AbstractJavaCodegen implements BeanValidationFeatures, OptionalFeatures, MicronautCodeGenerator<T> {

Expand All @@ -67,8 +73,9 @@ public abstract class AbstractMicronautJavaCodegen<T extends GeneratorOptionsBui
public static final String OPT_REQUIRED_PROPERTIES_IN_CONSTRUCTOR = "requiredPropertiesInConstructor";
public static final String OPT_USE_AUTH = "useAuth";
public static final String OPT_VISITABLE = "visitable";
public static final String OPT_DATE_LIBRARY_JAVA8 = "java8";
public static final String OPT_DATE_LIBRARY_JAVA8_LOCAL_DATETIME = "java8-localdatetime";
public static final String OPT_DATE_LIBRARY_ZONED_DATETIME = "ZONED_DATETIME";
public static final String OPT_DATE_LIBRARY_OFFSET_DATETIME = "OFFSET_DATETIME";
public static final String OPT_DATE_LIBRARY_LOCAL_DATETIME = "LOCAL_DATETIME";
public static final String OPT_DATE_FORMAT = "dateFormat";
public static final String OPT_DATETIME_FORMAT = "datetimeFormat";
public static final String OPT_REACTIVE = "reactive";
Expand All @@ -84,9 +91,6 @@ public abstract class AbstractMicronautJavaCodegen<T extends GeneratorOptionsBui
public static final String CONTENT_TYPE_APPLICATION_JSON = "application/json";
public static final String CONTENT_TYPE_MULTIPART_FORM_DATA = "multipart/form-data";
public static final String CONTENT_TYPE_ANY = "*/*";
public static final String DATE_FORMAT = "yyyy-MM-dd";
public static final String DATETIME_FORMAT = DATE_FORMAT + "'T'HH:mm:ss.SSS";
public static final String OFFSET_DATETIME_FORMAT = DATETIME_FORMAT + "XXXX";

protected String title;
protected boolean useBeanValidation;
Expand Down Expand Up @@ -122,7 +126,7 @@ protected AbstractMicronautJavaCodegen() {
embeddedTemplateDir = templateDir = "templates/java-micronaut";
apiDocPath = "docs/apis";
modelDocPath = "docs/models";
dateLibrary = OPT_DATE_LIBRARY_JAVA8;
dateLibrary = OPT_DATE_LIBRARY_ZONED_DATETIME;
reactive = true;
wrapInHttpResponse = false;
appName = artifactId;
Expand Down Expand Up @@ -189,8 +193,8 @@ protected AbstractMicronautJavaCodegen() {
// Modify the DATE_LIBRARY option to only have supported values
cliOptions.stream().filter(o -> o.getOpt().equals(DATE_LIBRARY)).findFirst().ifPresent(opt -> {
Map<String, String> valuesEnum = new HashMap<>();
valuesEnum.put(OPT_DATE_LIBRARY_JAVA8, opt.getEnum().get(OPT_DATE_LIBRARY_JAVA8));
valuesEnum.put(OPT_DATE_LIBRARY_JAVA8_LOCAL_DATETIME, opt.getEnum().get(OPT_DATE_LIBRARY_JAVA8_LOCAL_DATETIME));
valuesEnum.put(OPT_DATE_LIBRARY_OFFSET_DATETIME, opt.getEnum().get(OPT_DATE_LIBRARY_OFFSET_DATETIME));
valuesEnum.put(OPT_DATE_LIBRARY_LOCAL_DATETIME, opt.getEnum().get(OPT_DATE_LIBRARY_LOCAL_DATETIME));
opt.setEnum(valuesEnum);
});

Expand All @@ -208,6 +212,11 @@ protected AbstractMicronautJavaCodegen() {
"Authorization", "Body", "application"
};
reservedWords.addAll(Arrays.asList(reservedWordsArray));

importMapping.put("LocalDateTime", "java.time.LocalDateTime");
importMapping.put("OffsetDateTime", "java.time.OffsetDateTime");
importMapping.put("ZonedDateTime", "java.time.ZonedDateTime");
importMapping.put("LocalDate", "java.time.LocalDate");
}

public void setWrapInHttpResponse(boolean wrapInHttpResponse) {
Expand Down Expand Up @@ -335,19 +344,22 @@ public void processOpts() {
additionalProperties.put("javaxPackage", "jakarta");

// Use the default java time
additionalProperties.putIfAbsent(OPT_DATE_FORMAT, DATE_FORMAT);
if (dateLibrary.equals(OPT_DATE_LIBRARY_JAVA8)) {
typeMapping.put("DateTime", "OffsetDateTime");
typeMapping.put("date", "LocalDate");
additionalProperties.putIfAbsent(OPT_DATETIME_FORMAT, OFFSET_DATETIME_FORMAT);
} else if (dateLibrary.equals(OPT_DATE_LIBRARY_JAVA8_LOCAL_DATETIME)) {
typeMapping.put("DateTime", "LocalDateTime");
typeMapping.put("date", "LocalDate");
additionalProperties.putIfAbsent(OPT_DATETIME_FORMAT, DATETIME_FORMAT);
}
importMapping.putIfAbsent("LocalDateTime", "java.time.LocalDateTime");
importMapping.putIfAbsent("OffsetDateTime", "java.time.OffsetDateTime");
importMapping.putIfAbsent("LocalDate", "java.time.LocalDate");
switch (dateLibrary) {
case OPT_DATE_LIBRARY_OFFSET_DATETIME -> {
typeMapping.put("DateTime", "OffsetDateTime");
typeMapping.put("date", "LocalDate");
}
case OPT_DATE_LIBRARY_ZONED_DATETIME -> {
typeMapping.put("DateTime", "ZonedDateTime");
typeMapping.put("date", "LocalDate");
}
case OPT_DATE_LIBRARY_LOCAL_DATETIME -> {
typeMapping.put("DateTime", "LocalDateTime");
typeMapping.put("date", "LocalDate");
}
default -> {
}
}

// Add documentation files
modelDocTemplateFiles.clear();
Expand Down Expand Up @@ -587,12 +599,29 @@ public CodegenModel fromModel(String name, Schema model) {
return codegenModel;
}

@Override
public CodegenParameter fromParameter(Parameter param, Set<String> imports) {
CodegenParameter parameter = super.fromParameter(param, imports);
return parameter;
}

@Override
public boolean getUseInlineModelResolver() {
// This will allow TODO
return false;
}

@Override
public CodegenOperation fromOperation(String path, String httpMethod, Operation operation,
List<Server> servers) {
public CodegenOperation fromOperation(
String path, String httpMethod, Operation operation, List<Server> servers
) {
CodegenOperation op = super.fromOperation(path, httpMethod, operation, servers);

if (op.isResponseFile) {
op.returnType = typeMapping.get("responseFile");
op.imports.add(op.returnType);
}

op.vendorExtensions.put("originalParams", new ArrayList(op.allParams));
op.vendorExtensions.put("originReturnProperty", op.returnProperty);
processParametersWithAdditionalMappings(op.allParams, op.imports);
Expand Down Expand Up @@ -719,6 +748,7 @@ public Map<String, ModelsMap> postProcessAllModels(Map<String, ModelsMap> objs)
CodegenModel model = models.getModels().get(0).getModel();
if (model.getParentModel() != null) {
model.vendorExtensions.put("requiredParentVars", model.getParentModel().requiredVars);
model.parentVars = model.getParentModel().allVars;
}

List<CodegenProperty> requiredVars = model.vars.stream().filter(v -> v.required).collect(Collectors.toList());
Expand Down Expand Up @@ -881,6 +911,10 @@ public void setSerializationLibrary(final String serializationLibrary) {
}
}

public void setDateTimeLibrary(String name) {
setDateLibrary(name);
}

private static class ReplaceDotsWithUnderscoreLambda implements Mustache.Lambda {
@Override
public void execute(final Template.Fragment fragment, final Writer writer) throws IOException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
import java.util.Arrays;
import java.util.List;

/**
* The generator for creating Micronaut clients.
*/
@SuppressWarnings("checkstyle:DesignForExtension")
public class JavaMicronautClientCodegen extends AbstractMicronautJavaCodegen<JavaMicronautClientOptionsBuilder> {

Expand All @@ -44,6 +47,7 @@ public class JavaMicronautClientCodegen extends AbstractMicronautJavaCodegen<Jav
protected String clientId;

JavaMicronautClientCodegen() {
super();

title = "OpenAPI Micronaut Client";
configureAuthorization = false;
Expand All @@ -58,6 +62,9 @@ public class JavaMicronautClientCodegen extends AbstractMicronautJavaCodegen<Jav
cliOptions.add(CliOption.newString(AUTHORIZATION_FILTER_PATTERN, "Configure the authorization filter pattern for the client. Generally defined when generating clients from multiple specification files"));
cliOptions.add(CliOption.newString(BASE_PATH_SEPARATOR, "Configure the separator to use between the application name and base path when referencing the property").defaultValue(basePathSeparator));
cliOptions.add(CliOption.newString(CLIENT_ID, "Configure the service ID for the Client"));

typeMapping.put("file", "byte[]");
typeMapping.put("responseFile", "InputStream");
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
import java.util.Collections;
import java.util.List;

/**
* The generator for creating Micronaut servers.
*/
@SuppressWarnings("checkstyle:DesignForExtension")
public class JavaMicronautServerCodegen extends AbstractMicronautJavaCodegen<JavaMicronautServerOptionsBuilder> {

Expand All @@ -35,6 +38,7 @@ public class JavaMicronautServerCodegen extends AbstractMicronautJavaCodegen<Jav
public static final String OPT_GENERATE_IMPLEMENTATION_FILES = "generateImplementationFiles";
public static final String OPT_GENERATE_OPERATIONS_TO_RETURN_NOT_IMPLEMENTED = "generateOperationsToReturnNotImplemented";
public static final String OPT_GENERATE_HARD_NULLABLE = "generateHardNullable";
public static final String OPT_GENERATE_STREAMING_FILE_UPLOAD = "generateStreamingFileUpload";

public static final String EXTENSION_ROLES = "x-roles";
public static final String ANONYMOUS_ROLE_KEY = "isAnonymous()";
Expand All @@ -58,8 +62,10 @@ public class JavaMicronautServerCodegen extends AbstractMicronautJavaCodegen<Jav
protected boolean generateControllerFromExamples = false;
protected boolean useAuth = true;
protected boolean generateHardNullable = true;
protected boolean generateStreamingFileUpload = false;

JavaMicronautServerCodegen() {
super();

title = "OpenAPI Micronaut Server";
apiPackage = "org.openapitools.api";
Expand All @@ -83,12 +89,17 @@ public class JavaMicronautServerCodegen extends AbstractMicronautJavaCodegen<Jav

cliOptions.add(CliOption.newBoolean(OPT_USE_AUTH, "Whether to import authorization and to annotate controller methods accordingly", useAuth));
cliOptions.add(CliOption.newBoolean(OPT_GENERATE_HARD_NULLABLE, "Whether to generate and use an inherited nullable annotation", generateHardNullable));
cliOptions.add(CliOption.newBoolean(OPT_GENERATE_STREAMING_FILE_UPLOAD, "Whether to generate StreamingFileUpload type for file request body", generateStreamingFileUpload));


// Set the type mappings
// It could be also StreamingFileUpload
typeMapping.put("file", "CompletedFileUpload");
importMapping.put("CompletedFileUpload", "io.micronaut.http.multipart.CompletedFileUpload");
importMapping.put("StreamingFileUpload", "io.micronaut.http.multipart.StreamingFileUpload");

typeMapping.put("responseFile", "FileCustomizableResponseType");
importMapping.put("FileCustomizableResponseType", "io.micronaut.http.server.types.files.FileCustomizableResponseType");
}

@Override
Expand Down Expand Up @@ -167,6 +178,11 @@ public void processOpts() {
}
writePropertyBack(OPT_GENERATE_HARD_NULLABLE, generateHardNullable);

if (additionalProperties.containsKey(OPT_GENERATE_STREAMING_FILE_UPLOAD)) {
generateStreamingFileUpload = convertPropertyToBoolean(OPT_GENERATE_STREAMING_FILE_UPLOAD);
}
writePropertyBack(OPT_GENERATE_STREAMING_FILE_UPLOAD, generateStreamingFileUpload);

// Api file
apiTemplateFiles.clear();
setApiNamePrefix(API_PREFIX);
Expand Down Expand Up @@ -200,6 +216,10 @@ public void processOpts() {
String folder = (sourceFolder + '.' + invokerPackage + ".annotation").replace('.', File.separatorChar);
supportingFiles.add(new SupportingFile("server/HardNullable.mustache", folder, "HardNullable.java"));
}

if (generateStreamingFileUpload) {
typeMapping.put("file", "StreamingFileUpload");
}
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,10 @@ private void configureOptions() {
codeGenerator.setUseBeanValidation(options.beanValidation);
codeGenerator.setTestTool(options.testFramework.value);
codeGenerator.setSerializationLibrary(options.serializationLibraryKind().name());
codeGenerator.setDateTimeLibrary(options.dateTimeFormat().name());
configureServerOptions();
configureClientOptions();
codeGenerator.processOpts();
}

private void configureServerOptions() {
Expand Down Expand Up @@ -302,6 +304,7 @@ private static class DefaultOptionsBuilder implements MicronautCodeGeneratorOpti
private boolean wrapInHttpResponse;
private TestFramework testFramework = TestFramework.JUNIT5;
private SerializationLibraryKind serializationLibraryKind = SerializationLibraryKind.MICRONAUT_SERDE_JACKSON;
private DateTimeFormat dateTimeFormat = DateTimeFormat.ZONED_DATETIME;

@Override
public MicronautCodeGeneratorOptionsBuilder withApiPackage(String apiPackage) {
Expand Down Expand Up @@ -375,8 +378,14 @@ public MicronautCodeGeneratorOptionsBuilder withSerializationLibrary(Serializati
return this;
}

@Override
public MicronautCodeGeneratorOptionsBuilder withDateTimeFormat(DateTimeFormat format) {
dateTimeFormat = format;
return this;
}

private Options build() {
return new Options(apiPackage, modelPackage, invokerPackage, artifactId, parameterMappings, responseBodyMappings, beanValidation, optional, reactive, wrapInHttpResponse, testFramework, serializationLibraryKind);
return new Options(apiPackage, modelPackage, invokerPackage, artifactId, parameterMappings, responseBodyMappings, beanValidation, optional, reactive, wrapInHttpResponse, testFramework, serializationLibraryKind, dateTimeFormat);
}
}
}
Expand Down Expand Up @@ -408,7 +417,9 @@ private record Options(
boolean reactive,
boolean wrapInHttpResponse,
TestFramework testFramework,
SerializationLibraryKind serializationLibraryKind) {
SerializationLibraryKind serializationLibraryKind,
MicronautCodeGeneratorOptionsBuilder.DateTimeFormat dateTimeFormat
) {
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -112,5 +112,29 @@ public interface MicronautCodeGeneratorOptionsBuilder {
*/
MicronautCodeGeneratorOptionsBuilder withTestFramework(MicronautCodeGeneratorEntryPoint.TestFramework testFramework);

/**
* Configure the serialization library.
*
* @param library the serialization library.
* @return this builder
*/
MicronautCodeGeneratorOptionsBuilder withSerializationLibrary(SerializationLibraryKind library);

/**
* Configure the date-time format.
*
* @param format the date-time format.
* @return this builder
*/
MicronautCodeGeneratorOptionsBuilder withDateTimeFormat(DateTimeFormat format);

/**
* The possible date-time formatting configurations.
*/
enum DateTimeFormat {
OFFSET_DATETIME,
ZONED_DATETIME,
LOCAL_DATETIME;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
{{/generateSwagger2Annotations}}

{{#formatOneEmptyLine}}
{{#additionalClientTypeAnnotations}}
{{{.}}}
{{/additionalClientTypeAnnotations}}
Expand All @@ -50,6 +51,7 @@ public interface {{classname}} {
{{#operations}}

{{#operation}}
{{#formatNoEmptyLines}}
{{>common/operationAnnotations}}{{!
}} @{{#lambda.pascalcase}}{{#lambda.lowercase}}{{httpMethod}}{{/lambda.lowercase}}{{/lambda.pascalcase}}("{{{path}}}")
{{#hasProduces}}
Expand All @@ -66,8 +68,10 @@ public interface {{classname}} {
{{/configureAuth}}
{{!the method definition}}
{{>common/operationReturnType}} {{nickname}}({{#allParams}}
{{>client/params/queryParams}}{{>client/params/pathParams}}{{>client/params/headerParams}}{{>client/params/bodyParams}}{{>client/params/formParams}}{{>client/params/cookieParams}}{{^-last}}, {{/-last}}{{#-last}}
{{/-last}}{{/allParams}});
{{#formatSingleLine}}{{>client/params/queryParams}}{{>client/params/pathParams}}{{>client/params/headerParams}}{{>client/params/bodyParams}}{{>client/params/formParams}}{{>client/params/cookieParams}}{{^-last}},{{/-last}}{{/formatSingleLine}}
{{/allParams}});
{{/formatNoEmptyLines}}
{{/operation}}
{{/operations}}
}
{{/formatOneEmptyLine}}
Original file line number Diff line number Diff line change
Expand Up @@ -31,18 +31,26 @@
{{#jackson}}
{{^micronaut_serde_jackson}}
{{#isDateTime}}
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "{{{datetimeFormat}}}")
{{#datetimeFormat}}
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "{{{datetimeFormat}}}")
{{/datetimeFormat}}
{{/isDateTime}}
{{#isDate}}
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "{{{dateFormat}}}")
{{#dateFormat}}
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "{{{dateFormat}}}")
{{/dateFormat}}
{{/isDate}}
{{/micronaut_serde_jackson}}
{{/jackson}}
{{#micronaut_serde_jackson}}
{{#isDateTime}}
{{#datatimeFormat}}
@JsonFormat(pattern = "{{{datetimeFormat}}}")
{{/datatimeFormat}}
{{/isDateTime}}
{{#isDate}}
{{#dateFormat}}
@JsonFormat(pattern = "{{{dateFormat}}}")
{{/dateFormat}}
{{/isDate}}
{{/micronaut_serde_jackson}}
Loading

0 comments on commit 1fce141

Please sign in to comment.