From a85bd0f8f9785b6d7f215da56085bafb8c647016 Mon Sep 17 00:00:00 2001 From: Michal Foksa Date: Thu, 18 Jul 2019 06:28:40 +0200 Subject: [PATCH] Include common lambdas in generators (#3368) * Include commonly used Mustache lambdas in DefaultCodegen. * Use or extend common Mustache lambdas from DefaultCodegen. * Extract OnChangeLambda to own file. * Javadoc fixed in addMustacheLambdas(). --- .../openapitools/codegen/DefaultCodegen.java | 55 +++++++++++++++- .../languages/AbstractCSharpCodegen.java | 33 +++------- .../codegen/languages/AbstractCppCodegen.java | 31 +++------- .../languages/AbstractFSharpCodegen.java | 35 +++-------- .../languages/KotlinServerCodegen.java | 27 -------- .../languages/KotlinSpringServerCodegen.java | 21 +++---- .../languages/OpenAPIYamlGenerator.java | 62 +++---------------- .../ScalaPlayFrameworkServerCodegen.java | 16 +++-- .../templating/mustache/OnChangeLambda.java | 40 ++++++++++++ 9 files changed, 141 insertions(+), 179 deletions(-) create mode 100644 modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/mustache/OnChangeLambda.java diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java index 5373b99e934d..639f8448c3f2 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/DefaultCodegen.java @@ -19,7 +19,11 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.base.CaseFormat; +import com.google.common.collect.ImmutableMap; +import com.samskivert.mustache.Mustache; import com.samskivert.mustache.Mustache.Compiler; +import com.samskivert.mustache.Mustache.Lambda; + import io.swagger.v3.core.util.Json; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; @@ -48,6 +52,11 @@ import org.openapitools.codegen.meta.Stability; import org.openapitools.codegen.serializer.SerializerUtils; import org.openapitools.codegen.templating.MustacheEngineAdapter; +import org.openapitools.codegen.templating.mustache.CamelCaseLambda; +import org.openapitools.codegen.templating.mustache.IndentedLambda; +import org.openapitools.codegen.templating.mustache.LowercaseLambda; +import org.openapitools.codegen.templating.mustache.TitlecaseLambda; +import org.openapitools.codegen.templating.mustache.UppercaseLambda; import org.openapitools.codegen.utils.ModelUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -199,6 +208,47 @@ public void processOpts() { } } + /*** + * Preset map builder with commonly used Mustache lambdas. + * + * To extend the map, override addMustacheLambdas(), call parent method + * first and then add additional lambdas to the returned builder. + * + * If common lambdas are not desired, override addMustacheLambdas() method + * and return empty builder. + * + * @return preinitialized map builder with common lambdas + */ + protected ImmutableMap.Builder addMustacheLambdas() { + + return new ImmutableMap.Builder() + .put("lowercase", new LowercaseLambda().generator(this)) + .put("uppercase", new UppercaseLambda()) + .put("titlecase", new TitlecaseLambda()) + .put("camelcase", new CamelCaseLambda().generator(this)) + .put("indented", new IndentedLambda()) + .put("indented_8", new IndentedLambda(8, " ")) + .put("indented_12", new IndentedLambda(12, " ")) + .put("indented_16", new IndentedLambda(16, " ")); + } + + private void registerMustacheLambdas() { + ImmutableMap lambdas = addMustacheLambdas().build(); + + if (lambdas.size() == 0) { + return; + } + + if (additionalProperties.containsKey("lambda")) { + LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " + + "You'll likely need to use a custom template, " + + "see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/templating.md. "); + additionalProperties.put("_lambda", lambdas); + } else { + additionalProperties.put("lambda", lambdas); + } + } + // override with any special post-processing for all models @SuppressWarnings({"static-method", "unchecked"}) public Map postProcessAllModels(Map objs) { @@ -1060,6 +1110,9 @@ public DefaultCodegen() { // initialize special character mapping initalizeSpecialCharacterMapping(); + + // Register common Mustache lambdas. + registerMustacheLambdas(); } /** @@ -1523,7 +1576,7 @@ private String getPrimitiveType(Schema schema) { // If the format matches a typeMapping (supplied with the --typeMappings flag) // then treat the format as a primitive type. // This allows the typeMapping flag to add a new custom type which can then - // be used in the format field. + // be used in the format field. return schema.getFormat(); } return "string"; diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java index 1e7a454007f8..d39c6c07ab47 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCSharpCodegen.java @@ -17,8 +17,9 @@ package org.openapitools.codegen.languages; -import com.google.common.collect.ImmutableMap; -import com.samskivert.mustache.Mustache; +import com.google.common.collect.ImmutableMap.Builder; +import com.samskivert.mustache.Mustache.Lambda; + import io.swagger.v3.core.util.Json; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; @@ -359,32 +360,12 @@ public void processOpts() { // This either updates additionalProperties with the above fixes, or sets the default if the option was not specified. additionalProperties.put(CodegenConstants.INTERFACE_PREFIX, interfacePrefix); - - addMustacheLambdas(additionalProperties); } - private void addMustacheLambdas(Map objs) { - - Map lambdas = new ImmutableMap.Builder() - .put("lowercase", new LowercaseLambda().generator(this)) - .put("uppercase", new UppercaseLambda()) - .put("titlecase", new TitlecaseLambda()) - .put("camelcase", new CamelCaseLambda().generator(this)) - .put("camelcase_param", new CamelCaseLambda().generator(this).escapeAsParamName(true)) - .put("indented", new IndentedLambda()) - .put("indented_8", new IndentedLambda(8, " ")) - .put("indented_12", new IndentedLambda(12, " ")) - .put("indented_16", new IndentedLambda(16, " ")) - .build(); - - if (objs.containsKey("lambda")) { - LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " + - "You'll likely need to use a custom template, " + - "see https://github.com/swagger-api/swagger-codegen#modifying-the-client-library-format. "); - objs.put("_lambda", lambdas); - } else { - objs.put("lambda", lambdas); - } + @Override + protected Builder addMustacheLambdas() { + return super.addMustacheLambdas() + .put("camelcase_param", new CamelCaseLambda().generator(this).escapeAsParamName(true)); } @Override diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java index 65105e467a86..afbbae668485 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractCppCodegen.java @@ -17,8 +17,8 @@ package org.openapitools.codegen.languages; -import com.google.common.collect.ImmutableMap; -import com.samskivert.mustache.Mustache; +import com.google.common.collect.ImmutableMap.Builder; +import com.samskivert.mustache.Mustache.Lambda; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.Schema; @@ -35,7 +35,6 @@ import java.io.File; import java.net.URL; import java.util.Arrays; -import java.util.Map; abstract public class AbstractCppCodegen extends DefaultCodegen implements CodegenConfig { private static final Logger LOGGER = LoggerFactory.getLogger(AbstractCppCodegen.class); @@ -260,22 +259,12 @@ public void processOpts() { LOGGER.info("Environment variable CPP_POST_PROCESS_FILE not defined so the C++ code may not be properly formatted. To define it, try 'export CPP_POST_PROCESS_FILE=\"/usr/local/bin/clang-format -i\"' (Linux/Mac)"); LOGGER.info("NOTE: To enable file post-processing, 'enablePostProcessFile' must be set to `true` (--enable-post-process-file for CLI)."); } - - addMustacheLambdas(additionalProperties); } - private void addMustacheLambdas(Map objs) { - - Map lambdas = new ImmutableMap.Builder() - .put("multiline_comment_4", new IndentedLambda(4, " ", "///")) - .build(); - - if (objs.containsKey("lambda")) { - LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'."); - objs.put("_lambda", lambdas); - } else { - objs.put("lambda", lambdas); - } + @Override + protected Builder addMustacheLambdas() { + return super.addMustacheLambdas() + .put("multiline_comment_4", new IndentedLambda(4, " ", "///")); } @Override @@ -304,17 +293,17 @@ public void postProcessFile(File file, String fileType) { } } } - + @Override public void preprocessOpenAPI(OpenAPI openAPI) { URL url = URLPathUtils.getServerURL(openAPI); String port = URLPathUtils.getPort(url, ""); String host = url.getHost(); if(!port.isEmpty()) { - this.additionalProperties.put("serverPort", port); + this.additionalProperties.put("serverPort", port); } if(!host.isEmpty()) { - this.additionalProperties.put("serverHost", host); - } + this.additionalProperties.put("serverHost", host); + } } } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java index 9d82448ffb3b..04a626eac774 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractFSharpCodegen.java @@ -16,8 +16,9 @@ package org.openapitools.codegen.languages; -import com.google.common.collect.ImmutableMap; -import com.samskivert.mustache.Mustache; +import com.google.common.collect.ImmutableMap.Builder; +import com.samskivert.mustache.Mustache.Lambda; + import io.swagger.v3.core.util.Json; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; @@ -67,7 +68,7 @@ public abstract class AbstractFSharpCodegen extends DefaultCodegen implements Co protected Set collectionTypes; protected Set mapTypes; - // true if nullable types will be supported (as option) + // true if nullable types will be supported (as option) protected boolean supportNullable = Boolean.TRUE; protected Set nullableType = new HashSet(); @@ -329,32 +330,12 @@ public void processOpts() { // This either updates additionalProperties with the above fixes, or sets the default if the option was not specified. additionalProperties.put(CodegenConstants.INTERFACE_PREFIX, interfacePrefix); - - addMustacheLambdas(additionalProperties); } - private void addMustacheLambdas(Map objs) { - - Map lambdas = new ImmutableMap.Builder() - .put("lowercase", new LowercaseLambda().generator(this)) - .put("uppercase", new UppercaseLambda()) - .put("titlecase", new TitlecaseLambda()) - .put("camelcase", new CamelCaseLambda().generator(this)) - .put("camelcase_param", new CamelCaseLambda().generator(this).escapeAsParamName(true)) - .put("indented", new IndentedLambda()) - .put("indented_8", new IndentedLambda(8, " ")) - .put("indented_12", new IndentedLambda(12, " ")) - .put("indented_16", new IndentedLambda(16, " ")) - .build(); - - if (objs.containsKey("lambda")) { - LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " + - "You'll likely need to use a custom template, " + - "see https://github.com/swagger-api/swagger-codegen#modifying-the-client-library-format. "); - objs.put("_lambda", lambdas); - } else { - objs.put("lambda", lambdas); - } + @Override + protected Builder addMustacheLambdas() { + return super.addMustacheLambdas() + .put("camelcase_param", new CamelCaseLambda().generator(this).escapeAsParamName(true)); } @Override diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java index 80e48bf0bc02..4bd48eb2188e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinServerCodegen.java @@ -18,13 +18,11 @@ package org.openapitools.codegen.languages; import com.google.common.collect.ImmutableMap; -import com.samskivert.mustache.Mustache; import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.CliOption; import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenType; import org.openapitools.codegen.SupportingFile; -import org.openapitools.codegen.templating.mustache.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -211,31 +209,6 @@ public void processOpts() { final String infrastructureFolder = (sourceFolder + File.separator + packageName + File.separator + "infrastructure").replace(".", File.separator); supportingFiles.add(new SupportingFile("ApiKeyAuth.kt.mustache", infrastructureFolder, "ApiKeyAuth.kt")); - - addMustacheLambdas(additionalProperties); - } - - private void addMustacheLambdas(Map objs) { - - Map lambdas = new ImmutableMap.Builder() - .put("lowercase", new LowercaseLambda().generator(this)) - .put("uppercase", new UppercaseLambda()) - .put("titlecase", new TitlecaseLambda()) - .put("camelcase", new CamelCaseLambda().generator(this)) - .put("indented", new IndentedLambda()) - .put("indented_8", new IndentedLambda(8, " ")) - .put("indented_12", new IndentedLambda(12, " ")) - .put("indented_16", new IndentedLambda(16, " ")) - .build(); - - if (objs.containsKey("lambda")) { - LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " + - "You'll likely need to use a custom template, " + - "see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/templating.md. "); - objs.put("_lambda", lambdas); - } else { - objs.put("lambda", lambdas); - } } public static class Constants { diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java index 28e45eb7af4d..36c99c39a708 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/KotlinSpringServerCodegen.java @@ -16,9 +16,11 @@ package org.openapitools.codegen.languages; -import com.google.common.collect.ImmutableMap; +import com.google.common.collect.ImmutableMap.Builder; import com.samskivert.mustache.Mustache; import com.samskivert.mustache.Template; +import com.samskivert.mustache.Mustache.Lambda; + import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.media.Schema; import org.openapitools.codegen.*; @@ -51,7 +53,6 @@ public class KotlinSpringServerCodegen extends AbstractKotlinCodegen )); public static final String TITLE = "title"; - public static final String LAMBDA = "lambda"; public static final String SERVER_PORT = "serverPort"; public static final String BASE_PACKAGE = "basePackage"; public static final String SPRING_BOOT = "spring-boot"; @@ -370,22 +371,14 @@ public void processOpts() { sanitizeDirectory(sourceFolder + File.separator + basePackage), "Application.kt")); } - addMustacheLambdas(additionalProperties); - // spring uses the jackson lib, and we disallow configuration. additionalProperties.put("jackson", "true"); } - private void addMustacheLambdas(final Map objs) { - Map lambdas = - new ImmutableMap.Builder() - .put("escapeDoubleQuote", new EscapeLambda("\"", "\\\"")) - .build(); - - if (objs.containsKey(LAMBDA)) { - LOGGER.warn("The lambda property is a reserved word, and will be overwritten!"); - } - objs.put(LAMBDA, lambdas); + @Override + protected Builder addMustacheLambdas() { + return super.addMustacheLambdas() + .put("escapeDoubleQuote", new EscapeLambda("\"", "\\\"")); } @Override diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/OpenAPIYamlGenerator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/OpenAPIYamlGenerator.java index 5c46567fd940..ca1e91026643 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/OpenAPIYamlGenerator.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/OpenAPIYamlGenerator.java @@ -18,21 +18,15 @@ package org.openapitools.codegen.languages; import org.openapitools.codegen.*; -import org.openapitools.codegen.templating.mustache.CamelCaseLambda; -import org.openapitools.codegen.templating.mustache.IndentedLambda; -import org.openapitools.codegen.templating.mustache.LowercaseLambda; -import org.openapitools.codegen.templating.mustache.TitlecaseLambda; -import org.openapitools.codegen.templating.mustache.UppercaseLambda; +import org.openapitools.codegen.templating.mustache.OnChangeLambda; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.google.common.collect.ImmutableMap; -import com.samskivert.mustache.Mustache; -import com.samskivert.mustache.Template; +import com.google.common.collect.ImmutableMap.Builder; +import com.samskivert.mustache.Mustache.Lambda; + import io.swagger.v3.oas.models.Operation; -import java.io.IOException; -import java.io.Writer; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -75,32 +69,12 @@ public void processOpts() { } LOGGER.info("Output file [outputFile={}]", outputFile); supportingFiles.add(new SupportingFile("openapi.mustache", outputFile)); - - addMustacheLambdas(additionalProperties); } - private void addMustacheLambdas(Map objs) { - - Map lambdas = new ImmutableMap.Builder() - .put("lowercase", new LowercaseLambda().generator(this)) - .put("uppercase", new UppercaseLambda()) - .put("titlecase", new TitlecaseLambda()) - .put("camelcase", new CamelCaseLambda().generator(this)) - .put("indented", new IndentedLambda()) - .put("indented_8", new IndentedLambda(8, " ")) - .put("indented_12", new IndentedLambda(12, " ")) - .put("indented_16", new IndentedLambda(16, " ")) - .put("onchange", new OnChangeLambda()) - .build(); - - if (objs.containsKey("lambda")) { - LOGGER.warn("A property named 'lambda' already exists. Mustache lambdas renamed from 'lambda' to '_lambda'. " + - "You'll likely need to use a custom template, " + - "see https://github.com/OpenAPITools/openapi-generator/blob/master/docs/templating.md. "); - objs.put("_lambda", lambdas); - } else { - objs.put("lambda", lambdas); - } + @Override + protected Builder addMustacheLambdas() { + return super.addMustacheLambdas() + .put("onchange", new OnChangeLambda()); } /** @@ -133,24 +107,4 @@ public String escapeUnsafeCharacters(String input) { return input; } - /** - * Lambda writes current fragment to the output when it is different than - * previous fragment. - */ - public static class OnChangeLambda implements Mustache.Lambda { - private static final Logger LOGGER = LoggerFactory.getLogger(OnChangeLambda.class); - - private String lastVal = null; - - @Override - public void execute(Template.Fragment frag, Writer out) throws IOException { - String curVal = frag.execute(); - LOGGER.debug("[lastVal={}, curVal={}]", lastVal, curVal); - if (curVal != null && !curVal.equals(lastVal)) { - out.write(curVal); - lastVal = curVal; - } - } - } - } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaPlayFrameworkServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaPlayFrameworkServerCodegen.java index a30f0bd7972c..1f02cc989f4d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaPlayFrameworkServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaPlayFrameworkServerCodegen.java @@ -16,8 +16,9 @@ package org.openapitools.codegen.languages; -import com.google.common.collect.ImmutableMap; -import com.samskivert.mustache.Mustache; +import com.google.common.collect.ImmutableMap.Builder; +import com.samskivert.mustache.Mustache.Lambda; + import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; import org.openapitools.codegen.*; @@ -192,15 +193,12 @@ public void processOpts() { supportingFiles.add(new SupportingFile("public/openapi.json.mustache", "public", "openapi.json")); supportingFiles.add(new SupportingFile("app/apiDocController.scala.mustache", String.format(Locale.ROOT, "app/%s", apiPackage.replace(".", File.separator)), "ApiDocController.scala")); } - addMustacheLambdas(additionalProperties); } - private void addMustacheLambdas(Map objs) { - Map lambdas = new ImmutableMap.Builder() - .put("indented_4", new IndentedLambda(4, " ")) - .put("indented_8", new IndentedLambda(8, " ")) - .build(); - objs.put("lambda", lambdas); + @Override + protected Builder addMustacheLambdas() { + return super.addMustacheLambdas() + .put("indented_4", new IndentedLambda(4, " ")); } @SuppressWarnings("unchecked") diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/mustache/OnChangeLambda.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/mustache/OnChangeLambda.java new file mode 100644 index 000000000000..11efbfae5bb3 --- /dev/null +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/templating/mustache/OnChangeLambda.java @@ -0,0 +1,40 @@ +package org.openapitools.codegen.templating.mustache; + +import java.io.IOException; +import java.io.Writer; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.samskivert.mustache.Mustache; +import com.samskivert.mustache.Template; + +/** + * Lambda writes current fragment to the output when it is different than + * the previous fragment. + * + * Register: + *
+ * additionalProperties.put("onchange", new OnChangeLambda());
+ * 
+ * + * Use: + *
+ * {{#onchange}}{{name}}{{/onchange}}
+ * 
+ */ +public class OnChangeLambda implements Mustache.Lambda { + private static final Logger LOGGER = LoggerFactory.getLogger(OnChangeLambda.class); + + private String lastVal = null; + + @Override + public void execute(Template.Fragment frag, Writer out) throws IOException { + String curVal = frag.execute(); + LOGGER.debug("[lastVal={}, curVal={}]", lastVal, curVal); + if (curVal != null && !curVal.equals(lastVal)) { + out.write(curVal); + lastVal = curVal; + } + } +} \ No newline at end of file