From 05935094a1d8a3c1759b9660d00c2066e7504cee Mon Sep 17 00:00:00 2001 From: altro3 Date: Fri, 9 Feb 2024 14:26:42 +0700 Subject: [PATCH] Add support openapi-generator mapping configuration properties: schemaMapping importMapping nameMapping typeMapping enumNameMapping modelNameMapping Fixed #1421 --- .../openapi/OpenApiGeneratorTask.java | 5 + .../AbstractMicronautJavaCodegen.java | 24 ++++ .../AbstractMicronautKotlinCodegen.java | 26 ++++- .../MicronautCodeGeneratorEntryPoint.java | 110 +++++++++++++++++- .../MicronautCodeGeneratorOptionsBuilder.java | 48 ++++++++ .../openapi/testsuite/GeneratorMain.java | 41 ++++++- test-suite-java-server-generator/build.gradle | 1 + test-suite-java-server-generator/spec.yaml | 3 + 8 files changed, 254 insertions(+), 4 deletions(-) diff --git a/build-logic/src/main/groovy/io/micronaut/build/internal/openapi/OpenApiGeneratorTask.java b/build-logic/src/main/groovy/io/micronaut/build/internal/openapi/OpenApiGeneratorTask.java index e973b7ecfc..58882e5354 100644 --- a/build-logic/src/main/groovy/io/micronaut/build/internal/openapi/OpenApiGeneratorTask.java +++ b/build-logic/src/main/groovy/io/micronaut/build/internal/openapi/OpenApiGeneratorTask.java @@ -28,6 +28,7 @@ import org.gradle.api.file.DirectoryProperty; import org.gradle.api.file.RegularFileProperty; import org.gradle.api.provider.ListProperty; +import org.gradle.api.provider.MapProperty; import org.gradle.api.provider.Property; import org.gradle.api.provider.Provider; import org.gradle.api.tasks.Classpath; @@ -89,6 +90,9 @@ public Provider getGeneratedTestSourcesDirectory() { @Input public abstract ListProperty> getResponseBodyMappings(); + @Input + public abstract MapProperty getNameMapping(); + @Inject protected abstract ExecOperations getExecOperations(); @@ -115,6 +119,7 @@ public void execute() throws IOException { args.add(lang.toUpperCase()); args.add(Boolean.toString(generatedAnnotation)); args.add(Boolean.toString(ksp)); + args.add(getNameMapping().get().toString()); javaexec.args(args); }); } diff --git a/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautJavaCodegen.java b/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautJavaCodegen.java index 2dbebf22ab..14949242ab 100644 --- a/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautJavaCodegen.java +++ b/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautJavaCodegen.java @@ -472,6 +472,30 @@ public void addResponseBodyMappings(List responseBodyMappin this.responseBodyMappings.addAll(responseBodyMappings); } + public void addSchemaMapping(Map schemaMapping) { + this.schemaMapping.putAll(schemaMapping); + } + + public void addImportMapping(Map importMapping) { + this.importMapping.putAll(importMapping); + } + + public void addNameMapping(Map nameMapping) { + this.nameMapping.putAll(nameMapping); + } + + public void addTypeMapping(Map typeMapping) { + this.typeMapping.putAll(typeMapping); + } + + public void addEnumNameMapping(Map enumNameMapping) { + this.enumNameMapping.putAll(enumNameMapping); + } + + public void addModelNameMapping(Map modelNameMapping) { + this.modelNameMapping.putAll(modelNameMapping); + } + // CHECKSTYLE:OFF private void maybeSetSwagger() { if (additionalProperties.containsKey(OPT_GENERATE_SWAGGER_ANNOTATIONS)) { diff --git a/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java b/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java index 8b0e8ffd43..4ba6c4c9d1 100644 --- a/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java +++ b/openapi-generator/src/main/java/io/micronaut/openapi/generator/AbstractMicronautKotlinCodegen.java @@ -554,6 +554,30 @@ public void addResponseBodyMappings(List responseBodyMappin this.responseBodyMappings.addAll(responseBodyMappings); } + public void addSchemaMapping(Map schemaMapping) { + this.schemaMapping.putAll(schemaMapping); + } + + public void addImportMapping(Map importMapping) { + this.importMapping.putAll(importMapping); + } + + public void addNameMapping(Map nameMapping) { + this.nameMapping.putAll(nameMapping); + } + + public void addTypeMapping(Map typeMapping) { + this.typeMapping.putAll(typeMapping); + } + + public void addEnumNameMapping(Map enumNameMapping) { + this.enumNameMapping.putAll(enumNameMapping); + } + + public void addModelNameMapping(Map modelNameMapping) { + this.modelNameMapping.putAll(modelNameMapping); + } + // CHECKSTYLE:OFF private void maybeSetSwagger() { if (additionalProperties.containsKey(OPT_GENERATE_SWAGGER_ANNOTATIONS)) { @@ -812,7 +836,7 @@ public String getTypeDeclaration(Schema p) { if (ModelUtils.isMapSchema(target)) { // Note: ModelUtils.isMapSchema(p) returns true when p is a composed schema that also defines - // additionalproperties: true + // additionalProperties: true Schema inner = ModelUtils.getAdditionalProperties(target); if (inner == null) { System.err.println("`" + p.getName() + "` (map property) does not have a proper inner type defined. Default to type:string"); diff --git a/openapi-generator/src/main/java/io/micronaut/openapi/generator/MicronautCodeGeneratorEntryPoint.java b/openapi-generator/src/main/java/io/micronaut/openapi/generator/MicronautCodeGeneratorEntryPoint.java index ca14147da5..e072dcd82e 100644 --- a/openapi-generator/src/main/java/io/micronaut/openapi/generator/MicronautCodeGeneratorEntryPoint.java +++ b/openapi-generator/src/main/java/io/micronaut/openapi/generator/MicronautCodeGeneratorEntryPoint.java @@ -21,6 +21,7 @@ import java.util.Arrays; import java.util.EnumSet; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.Consumer; @@ -57,7 +58,7 @@ private MicronautCodeGeneratorEntryPoint(URI definitionFile, JavaMicronautClientCodegen.ClientOptions javaClientOptions, KotlinMicronautServerCodegen.ServerOptions kotlinServerOptions, KotlinMicronautClientCodegen.ClientOptions kotlinClientOptions - ) { + ) { this.definitionFile = definitionFile; this.outputDirectory = outputDirectory; this.codeGenerator = codeGenerator; @@ -141,6 +142,24 @@ private void configureOptions() { if (options.responseBodyMappings != null) { javaCodeGen.addResponseBodyMappings(options.responseBodyMappings); } + if (options.schemaMapping != null) { + javaCodeGen.addSchemaMapping(options.schemaMapping); + } + if (options.importMapping != null) { + javaCodeGen.addImportMapping(options.importMapping); + } + if (options.nameMapping != null) { + javaCodeGen.addNameMapping(options.nameMapping); + } + if (options.typeMapping != null) { + javaCodeGen.addTypeMapping(options.typeMapping); + } + if (options.enumNameMapping != null) { + javaCodeGen.addEnumNameMapping(options.enumNameMapping); + } + if (options.modelNameMapping != null) { + javaCodeGen.addModelNameMapping(options.modelNameMapping); + } javaCodeGen.setReactive(options.reactive); javaCodeGen.setGenerateHttpResponseAlways(options.generateHttpResponseAlways); javaCodeGen.setGenerateHttpResponseWhereRequired(options.generateHttpResponseWhereRequired); @@ -165,6 +184,24 @@ private void configureOptions() { if (options.responseBodyMappings != null) { kotlinCodeGen.addResponseBodyMappings(options.responseBodyMappings); } + if (options.schemaMapping != null) { + kotlinCodeGen.addSchemaMapping(options.schemaMapping); + } + if (options.importMapping != null) { + kotlinCodeGen.addImportMapping(options.importMapping); + } + if (options.nameMapping != null) { + kotlinCodeGen.addNameMapping(options.nameMapping); + } + if (options.typeMapping != null) { + kotlinCodeGen.addTypeMapping(options.typeMapping); + } + if (options.enumNameMapping != null) { + kotlinCodeGen.addEnumNameMapping(options.enumNameMapping); + } + if (options.modelNameMapping != null) { + kotlinCodeGen.addModelNameMapping(options.modelNameMapping); + } kotlinCodeGen.setReactive(options.reactive); kotlinCodeGen.setGenerateHttpResponseAlways(options.generateHttpResponseAlways); kotlinCodeGen.setGenerateHttpResponseWhereRequired(options.generateHttpResponseWhereRequired); @@ -413,6 +450,12 @@ private static class DefaultOptionsBuilder implements MicronautCodeGeneratorOpti private String modelPackage; private List parameterMappings; private List responseBodyMappings; + private Map schemaMapping; + private Map importMapping; + private Map nameMapping; + private Map typeMapping; + private Map enumNameMapping; + private Map modelNameMapping; private boolean optional; private boolean reactive = true; private boolean generateHttpResponseAlways; @@ -464,6 +507,42 @@ public MicronautCodeGeneratorOptionsBuilder withResponseBodyMappings(List schemaMapping) { + this.schemaMapping = schemaMapping; + return this; + } + + @Override + public MicronautCodeGeneratorOptionsBuilder withImportMapping(Map importMapping) { + this.importMapping = importMapping; + return this; + } + + @Override + public MicronautCodeGeneratorOptionsBuilder withNameMapping(Map nameMapping) { + this.nameMapping = nameMapping; + return this; + } + + @Override + public MicronautCodeGeneratorOptionsBuilder withTypeMapping(Map typeMapping) { + this.typeMapping = typeMapping; + return this; + } + + @Override + public MicronautCodeGeneratorOptionsBuilder withEnumNameMapping(Map enumNameMapping) { + this.enumNameMapping = enumNameMapping; + return this; + } + + @Override + public MicronautCodeGeneratorOptionsBuilder withModelNameMapping(Map modelNameMapping) { + this.modelNameMapping = modelNameMapping; + return this; + } + @Override public MicronautCodeGeneratorOptionsBuilder withReactive(boolean reactive) { this.reactive = reactive; @@ -513,7 +592,28 @@ public MicronautCodeGeneratorOptionsBuilder withDateTimeFormat(DateTimeFormat fo } private Options build() { - return new Options(lang, apiPackage, modelPackage, invokerPackage, artifactId, parameterMappings, responseBodyMappings, beanValidation, optional, reactive, generateHttpResponseAlways, generateHttpResponseWhereRequired, testFramework, serializationLibraryKind, dateTimeFormat); + return new Options( + lang, + apiPackage, + modelPackage, + invokerPackage, + artifactId, + parameterMappings, + responseBodyMappings, + schemaMapping, + importMapping, + nameMapping, + typeMapping, + enumNameMapping, + modelNameMapping, + beanValidation, + optional, + reactive, + generateHttpResponseAlways, + generateHttpResponseWhereRequired, + testFramework, + serializationLibraryKind, + dateTimeFormat); } } } @@ -542,6 +642,12 @@ private record Options( String artifactId, List parameterMappings, List responseBodyMappings, + Map schemaMapping, + Map importMapping, + Map nameMapping, + Map typeMapping, + Map enumNameMapping, + Map modelNameMapping, boolean beanValidation, boolean optional, boolean reactive, diff --git a/openapi-generator/src/main/java/io/micronaut/openapi/generator/MicronautCodeGeneratorOptionsBuilder.java b/openapi-generator/src/main/java/io/micronaut/openapi/generator/MicronautCodeGeneratorOptionsBuilder.java index 1119558a4a..d80a257872 100644 --- a/openapi-generator/src/main/java/io/micronaut/openapi/generator/MicronautCodeGeneratorOptionsBuilder.java +++ b/openapi-generator/src/main/java/io/micronaut/openapi/generator/MicronautCodeGeneratorOptionsBuilder.java @@ -16,6 +16,7 @@ package io.micronaut.openapi.generator; import java.util.List; +import java.util.Map; /** * Builder for generic options that the Micronaut code generator supports. @@ -79,6 +80,53 @@ public interface MicronautCodeGeneratorOptionsBuilder { */ MicronautCodeGeneratorOptionsBuilder withResponseBodyMappings(List responseBodyMappings); + /** + * Add the schema mappings. + * + * @param schemaMapping the schema mappings + * @return this builder + */ + MicronautCodeGeneratorOptionsBuilder withSchemaMapping(Map schemaMapping); + + /** + * Add the import mappings. + * + * @param importMapping the import mappings + * @return this builder + */ + MicronautCodeGeneratorOptionsBuilder withImportMapping(Map importMapping); + + /** + * Add the name mappings. + * + * @param nameMapping the name mappings + * @return this builder + */ + MicronautCodeGeneratorOptionsBuilder withNameMapping(Map nameMapping); + + /** + * Add the type mappings. + * + * @param typeMapping the type mappings + * @return this builder + */ + MicronautCodeGeneratorOptionsBuilder withTypeMapping(Map typeMapping); + + /** + * Add the enum name mappings. + * + * @param enumNameMapping the enum name mappings + * @return this builder + */ + MicronautCodeGeneratorOptionsBuilder withEnumNameMapping(Map enumNameMapping); + + /** + * Add the model name mappings. + * + * @param modelNameMapping the model name mappings + * @return this builder + */ + MicronautCodeGeneratorOptionsBuilder withModelNameMapping(Map modelNameMapping); /** * If set to true, the generator will use reactive types. diff --git a/test-suite-generator-util/src/main/java/io/micronaut/openapi/testsuite/GeneratorMain.java b/test-suite-generator-util/src/main/java/io/micronaut/openapi/testsuite/GeneratorMain.java index cc0be0bbb8..f599f3783f 100644 --- a/test-suite-generator-util/src/main/java/io/micronaut/openapi/testsuite/GeneratorMain.java +++ b/test-suite-generator-util/src/main/java/io/micronaut/openapi/testsuite/GeneratorMain.java @@ -60,6 +60,8 @@ public static void main(String[] args) throws URISyntaxException { List responseBodyMappings = parseResponseBodyMappings(args[5]); + Map nameMapping = parseNameMapping(args[8]); + MicronautCodeGeneratorEntryPoint.OutputKind[] outputKinds = Arrays.stream(args[3].split(",")) .map(MicronautCodeGeneratorEntryPoint.OutputKind::of) @@ -79,7 +81,8 @@ public static void main(String[] args) throws URISyntaxException { .withReactive(true) .withTestFramework(lang == JAVA ? MicronautCodeGeneratorEntryPoint.TestFramework.SPOCK : MicronautCodeGeneratorEntryPoint.TestFramework.JUNIT5) .withParameterMappings(parameterMappings) - .withResponseBodyMappings(responseBodyMappings); + .withResponseBodyMappings(responseBodyMappings) + .withNameMapping(nameMapping); }); if (server) { if (lang == GeneratorLanguage.KOTLIN) { @@ -136,6 +139,10 @@ private static List parseResponseBodyMappings(String string )).toList(); } + private static Map parseNameMapping(String string) { + return parseMap(string); + } + private static List> parseListOfMaps(String string) { List> result = new ArrayList<>(); if (string.isBlank()) { @@ -183,4 +190,36 @@ private static List> parseListOfMaps(String string) { return result; } + + private static Map parseMap(String string) { + var result = new HashMap(); + if (string.isBlank()) { + return result; + } + + assert string.charAt(0) == '{'; + int i = 1; + + int endIndex = string.indexOf('}', i); + + while (i < endIndex) { + if (string.charAt(i) == ' ') { + ++i; + } + int nameIndex = string.indexOf('=', i); + String name = string.substring(i, nameIndex); + i = nameIndex + 1; + int valueIndex = string.indexOf(',', i); + if (endIndex < valueIndex || valueIndex == -1) { + valueIndex = endIndex; + } + String value = string.substring(i, valueIndex); + i = valueIndex + 1; + + result.put(name, value); + } + assert i == string.length() - 1; + + return result; + } } diff --git a/test-suite-java-server-generator/build.gradle b/test-suite-java-server-generator/build.gradle index 40d3488b5f..1e41665221 100644 --- a/test-suite-java-server-generator/build.gradle +++ b/test-suite-java-server-generator/build.gradle @@ -68,4 +68,5 @@ tasks.named("generateOpenApi") { // Ignored header - Does not wrap the response in HttpResponse [headerName: "ignored-header"] ] + nameMapping = [test: "changedTest"] } diff --git a/test-suite-java-server-generator/spec.yaml b/test-suite-java-server-generator/spec.yaml index 3328d4fb79..befec924ef 100644 --- a/test-suite-java-server-generator/spec.yaml +++ b/test-suite-java-server-generator/spec.yaml @@ -895,6 +895,9 @@ components: message: type: string description: The error message + test: + type: string + description: Test prop parameters: PageQueryParam: