From 0adc20f1142cd9fe49dbe537206c34b6152d6425 Mon Sep 17 00:00:00 2001 From: Ghufz <18732053+Ghufz@users.noreply.github.com> Date: Fri, 17 Apr 2020 20:38:48 +0530 Subject: [PATCH 01/21] [powershell-experimental] ValidatePattern with double-quote (") throws-exception (#5956) * ValidatePattern having double quote(") throws exception on running Build.ps1 * fix tab with space Co-authored-by: Ghufran Zahidi --- .../PowerShellExperimentalClientCodegen.java | 23 +++++++++++++++++++ .../resources/3_0/powershell/petstore.yaml | 1 + .../src/PSPetstore/Model/User.ps1 | 1 + 3 files changed, 25 insertions(+) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java index 2b5ae61765c..5896ee99efe 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PowerShellExperimentalClientCodegen.java @@ -19,6 +19,7 @@ package org.openapitools.codegen.languages; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.Schema; import org.apache.commons.io.FilenameUtils; +import org.apache.commons.lang3.StringEscapeUtils; import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.*; import org.openapitools.codegen.meta.GeneratorMetadata; @@ -622,6 +623,28 @@ public class PowerShellExperimentalClientCodegen extends DefaultCodegen implemen supportingFiles.add(new SupportingFile("appveyor.mustache", "", "appveyor.yml")); } + @SuppressWarnings("static-method") + @Override + public String escapeText(String input) { + + if (input == null) { + return input; + } + + // remove \t, \n, \r + // replace \ with \\ + // replace " with \" + // outter unescape to retain the original multi-byte characters + // finally escalate characters avoiding code injection + return escapeUnsafeCharacters( + StringEscapeUtils.unescapeJava( + StringEscapeUtils.escapeJava(input) + .replace("\\/", "/")) + .replaceAll("[\\t\\n\\r]", " ") + .replace("\\", "\\\\") + .replace("\"", "\"\"")); + } + @Override public String escapeUnsafeCharacters(String input) { return input.replace("#>", "#_>").replace("<#", "<_#"); diff --git a/modules/openapi-generator/src/test/resources/3_0/powershell/petstore.yaml b/modules/openapi-generator/src/test/resources/3_0/powershell/petstore.yaml index a2e1dbaefa6..11ed2854ba5 100644 --- a/modules/openapi-generator/src/test/resources/3_0/powershell/petstore.yaml +++ b/modules/openapi-generator/src/test/resources/3_0/powershell/petstore.yaml @@ -689,6 +689,7 @@ components: type: string password: type: string + pattern: '["A-Z]+-[0-9][0-9]' phone: type: string userStatus: diff --git a/samples/client/petstore/powershell-experimental/src/PSPetstore/Model/User.ps1 b/samples/client/petstore/powershell-experimental/src/PSPetstore/Model/User.ps1 index a0147c19298..7e99caf62fb 100644 --- a/samples/client/petstore/powershell-experimental/src/PSPetstore/Model/User.ps1 +++ b/samples/client/petstore/powershell-experimental/src/PSPetstore/Model/User.ps1 @@ -62,6 +62,7 @@ function Initialize-PSUser { [String] ${Email}, [Parameter(Position = 5, ValueFromPipelineByPropertyName = $true)] + [ValidatePattern("[""A-Z]+-[0-9][0-9]")] [String] ${Password}, [Parameter(Position = 6, ValueFromPipelineByPropertyName = $true)] From cb50ad590f82304df534c8d244c0639abe1406bb Mon Sep 17 00:00:00 2001 From: Bouillie <34162532+Bouillie@users.noreply.github.com> Date: Fri, 17 Apr 2020 19:22:24 +0200 Subject: [PATCH 02/21] [scala-akka-http-server] Fix a generation problem on operations with empty responses (#5868) * [scala-akka-http-server] When expecting an empty response, a response with an empty text/plain content is not produced anymore * Updated scala-akka-http-server samples Co-authored-by: Olivier Leonard --- .../codegen/languages/ScalaAkkaHttpServerCodegen.java | 1 + .../src/main/resources/scala-akka-http-server/api.mustache | 6 ++++-- .../src/main/scala/org/openapitools/server/api/PetApi.scala | 1 + .../main/scala/org/openapitools/server/api/StoreApi.scala | 1 + .../main/scala/org/openapitools/server/api/UserApi.scala | 1 + 5 files changed, 8 insertions(+), 2 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaAkkaHttpServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaAkkaHttpServerCodegen.java index 4b98b531b26..d8c33f499da 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaAkkaHttpServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ScalaAkkaHttpServerCodegen.java @@ -409,6 +409,7 @@ public class ScalaAkkaHttpServerCodegen extends AbstractScalaCodegen implements entityMarshallerTypes.add(marshaller); operationSpecificMarshallers.add(marshaller); } + response.vendorExtensions.put("x-empty-response", response.baseType == null && response.message == null); response.vendorExtensions.put("x-is-default", response.code.equals("0")); } op.vendorExtensions.put("x-specific-marshallers", operationSpecificMarshallers); diff --git a/modules/openapi-generator/src/main/resources/scala-akka-http-server/api.mustache b/modules/openapi-generator/src/main/resources/scala-akka-http-server/api.mustache index cc9e7b69039..b680bb05503 100644 --- a/modules/openapi-generator/src/main/resources/scala-akka-http-server/api.mustache +++ b/modules/openapi-generator/src/main/resources/scala-akka-http-server/api.mustache @@ -2,6 +2,7 @@ package {{package}} import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route +import akka.http.scaladsl.model.StatusCodes {{^pathMatcherPatterns.isEmpty}}import akka.http.scaladsl.server.{PathMatcher, PathMatcher1} {{/pathMatcherPatterns.isEmpty}} {{#hasMarshalling}}import akka.http.scaladsl.marshalling.ToEntityMarshaller @@ -63,8 +64,9 @@ object {{classname}}Patterns { trait {{classname}}Service { {{#operation}} -{{#responses}} def {{operationId}}{{#vendorExtensions.x-is-default}}Default{{/vendorExtensions.x-is-default}}{{^vendorExtensions.x-is-default}}{{code}}{{/vendorExtensions.x-is-default}}{{#baseType}}({{#vendorExtensions.x-is-default}}statusCode: Int, {{/vendorExtensions.x-is-default}}response{{baseType}}{{containerType}}: {{dataType}}){{^isPrimitiveType}}(implicit toEntityMarshaller{{baseType}}{{containerType}}: ToEntityMarshaller[{{dataType}}]){{/isPrimitiveType}}{{/baseType}}{{^baseType}}{{#vendorExtensions.x-is-default}}(statusCode: Int){{/vendorExtensions.x-is-default}}{{/baseType}}: Route = - complete(({{#vendorExtensions.x-is-default}}statusCode{{/vendorExtensions.x-is-default}}{{^vendorExtensions.x-is-default}}{{code}}{{/vendorExtensions.x-is-default}}, {{#baseType}}response{{baseType}}{{containerType}}{{/baseType}}{{^baseType}}"{{message}}"{{/baseType}})) +{{#responses}} def {{operationId}}{{#vendorExtensions.x-is-default}}Default{{/vendorExtensions.x-is-default}}{{^vendorExtensions.x-is-default}}{{code}}{{/vendorExtensions.x-is-default}}{{#baseType}}({{#vendorExtensions.x-is-default}}statusCode: Int, {{/vendorExtensions.x-is-default}}response{{baseType}}{{containerType}}: {{dataType}}){{^isPrimitiveType}}(implicit toEntityMarshaller{{baseType}}{{containerType}}: ToEntityMarshaller[{{dataType}}]){{/isPrimitiveType}}{{/baseType}}{{^baseType}}{{#vendorExtensions.x-is-default}}(statusCode: Int){{/vendorExtensions.x-is-default}}{{/baseType}}: Route ={{#vendorExtensions.x-empty-response}} + complete({{#vendorExtensions.x-is-default}}statusCode{{/vendorExtensions.x-is-default}}{{^vendorExtensions.x-is-default}}StatusCodes.getForKey({{code}}){{/vendorExtensions.x-is-default}}){{/vendorExtensions.x-empty-response}}{{^vendorExtensions.x-empty-response}} + complete(({{#vendorExtensions.x-is-default}}statusCode{{/vendorExtensions.x-is-default}}{{^vendorExtensions.x-is-default}}{{code}}{{/vendorExtensions.x-is-default}}, {{#baseType}}response{{baseType}}{{containerType}}{{/baseType}}{{^baseType}}"{{message}}"{{/baseType}})){{/vendorExtensions.x-empty-response}} {{/responses}} /** {{#responses}} * {{#code}}Code: {{.}}{{/code}}{{#message}}, Message: {{.}}{{/message}}{{#dataType}}, DataType: {{.}}{{/dataType}} diff --git a/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/PetApi.scala b/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/PetApi.scala index a78bb32e9a5..4c437290a56 100644 --- a/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/PetApi.scala +++ b/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/PetApi.scala @@ -2,6 +2,7 @@ package org.openapitools.server.api import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route +import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.marshalling.ToEntityMarshaller import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller import akka.http.scaladsl.unmarshalling.FromStringUnmarshaller diff --git a/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/StoreApi.scala b/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/StoreApi.scala index a7bfdc65012..7d8a1743b0e 100644 --- a/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/StoreApi.scala +++ b/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/StoreApi.scala @@ -2,6 +2,7 @@ package org.openapitools.server.api import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route +import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.marshalling.ToEntityMarshaller import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller import akka.http.scaladsl.unmarshalling.FromStringUnmarshaller diff --git a/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/UserApi.scala b/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/UserApi.scala index 0d8cdff7694..2470f1e036c 100644 --- a/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/UserApi.scala +++ b/samples/server/petstore/scala-akka-http-server/src/main/scala/org/openapitools/server/api/UserApi.scala @@ -2,6 +2,7 @@ package org.openapitools.server.api import akka.http.scaladsl.server.Directives._ import akka.http.scaladsl.server.Route +import akka.http.scaladsl.model.StatusCodes import akka.http.scaladsl.marshalling.ToEntityMarshaller import akka.http.scaladsl.unmarshalling.FromEntityUnmarshaller import akka.http.scaladsl.unmarshalling.FromStringUnmarshaller From e47739dda55a58154b38c35ab2dfafad626e1867 Mon Sep 17 00:00:00 2001 From: Fabian Freund Date: Sat, 18 Apr 2020 03:57:18 +0200 Subject: [PATCH 03/21] return a null instead of application/json when no content types are set (#5941) * return a null instead of application/json when no content types are set * update petstore sample Co-authored-by: William Cheng --- .../src/main/resources/csharp-netcore/ClientUtils.mustache | 2 +- .../OpenAPIClient/src/Org.OpenAPITools/Client/ClientUtils.cs | 2 +- .../src/Org.OpenAPITools/Client/ClientUtils.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp-netcore/ClientUtils.mustache b/modules/openapi-generator/src/main/resources/csharp-netcore/ClientUtils.mustache index b407a4edd08..f756a2c86ae 100755 --- a/modules/openapi-generator/src/main/resources/csharp-netcore/ClientUtils.mustache +++ b/modules/openapi-generator/src/main/resources/csharp-netcore/ClientUtils.mustache @@ -169,7 +169,7 @@ namespace {{packageName}}.Client public static String SelectHeaderContentType(String[] contentTypes) { if (contentTypes.Length == 0) - return "application/json"; + return null; foreach (var contentType in contentTypes) { diff --git a/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/ClientUtils.cs b/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/ClientUtils.cs index 9bd20d5f576..65d7da67f6a 100644 --- a/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/ClientUtils.cs +++ b/samples/client/petstore/csharp-netcore/OpenAPIClient/src/Org.OpenAPITools/Client/ClientUtils.cs @@ -174,7 +174,7 @@ namespace Org.OpenAPITools.Client public static String SelectHeaderContentType(String[] contentTypes) { if (contentTypes.Length == 0) - return "application/json"; + return null; foreach (var contentType in contentTypes) { diff --git a/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/ClientUtils.cs b/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/ClientUtils.cs index 9bd20d5f576..65d7da67f6a 100644 --- a/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/ClientUtils.cs +++ b/samples/client/petstore/csharp-netcore/OpenAPIClientCore/src/Org.OpenAPITools/Client/ClientUtils.cs @@ -174,7 +174,7 @@ namespace Org.OpenAPITools.Client public static String SelectHeaderContentType(String[] contentTypes) { if (contentTypes.Length == 0) - return "application/json"; + return null; foreach (var contentType in contentTypes) { From c5472be422eb8508abbe2a7cb6d4b623f3df6158 Mon Sep 17 00:00:00 2001 From: Alexey Makhrov Date: Sat, 18 Apr 2020 00:22:20 -0700 Subject: [PATCH 04/21] Ensure `model.allParents` always includes `model.parent`. (#5738) `allParents` is used by generators with multiple inheritance, e.g typescript and perl --- .../org/openapitools/codegen/utils/ModelUtils.java | 11 +++++------ .../org/openapitools/codegen/DefaultCodegenTest.java | 12 ++++++++++++ 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java index e55479e4a31..8dac545365a 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/utils/ModelUtils.java @@ -1236,7 +1236,6 @@ public class ModelUtils { public static List getAllParentsName(ComposedSchema composedSchema, Map allSchemas, boolean includeAncestors) { List interfaces = getInterfaces(composedSchema); List names = new ArrayList(); - List refedWithoutDiscriminator = new ArrayList<>(); if (interfaces != null && !interfaces.isEmpty()) { for (Schema schema : interfaces) { @@ -1255,7 +1254,6 @@ public class ModelUtils { } } else { // not a parent since discriminator.propertyName is not set - refedWithoutDiscriminator.add(parentName); } } else { // not a ref, doing nothing @@ -1263,10 +1261,11 @@ public class ModelUtils { } } - if (names.size() == 0 && refedWithoutDiscriminator.size() == 1) { - LOGGER.warn("[deprecated] inheritance without use of 'discriminator.propertyName' is deprecated " + - "and will be removed in a future release. Generating model for {}. Title: {}", composedSchema.getName(), composedSchema.getTitle()); - return refedWithoutDiscriminator; + // ensure `allParents` always includes `parent` + // this is more robust than keeping logic in getParentName() and getAllParentsName() in sync + String parentName = getParentName(composedSchema, allSchemas); + if (parentName != null && !names.contains(parentName)) { + names.add(parentName); } return names; diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java index ead422552b7..e655027890e 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultCodegenTest.java @@ -604,6 +604,18 @@ public class DefaultCodegenTest { Assert.assertEquals(getRequiredVars(childModel), Collections.singletonList("name")); } + @Test + public void testAllOfSingleRefWithOwnPropsNoDiscriminator() { + final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/2_0/composed-allof.yaml"); + final DefaultCodegen codegen = new CodegenWithMultipleInheritance(); + + Schema schema = openAPI.getComponents().getSchemas().get("MessageEventCoreWithTimeListEntries"); + codegen.setOpenAPI(openAPI); + CodegenModel model = codegen.fromModel("MessageEventCoreWithTimeListEntries", schema); + Assert.assertEquals(model.parent, "MessageEventCore"); + Assert.assertEquals(model.allParents, Collections.singletonList("MessageEventCore")); + } + @Test public void testAllOfSingleRefNoOwnProps() { final OpenAPI openAPI = TestUtils.parseFlattenSpec("src/test/resources/2_0/composed-allof.yaml"); From 84099eefdc7fe4f5a9b7726e376fc01189ae355d Mon Sep 17 00:00:00 2001 From: Falko Modler Date: Sun, 19 Apr 2020 02:40:09 +0200 Subject: [PATCH 05/21] =?UTF-8?q?[maven]=20mark=20Mojo=20threadSafe=3Dtrue?= =?UTF-8?q?=20+=20fix=20concurrency=20issue=20in=20Co=E2=80=A6=20(#5898)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../codegen/plugin/CodeGenMojo.java | 2 +- .../codegen/config/CodegenConfigurator.java | 115 +++++++++--------- 2 files changed, 61 insertions(+), 56 deletions(-) diff --git a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java index aa386a2995f..0d33707e32d 100644 --- a/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java +++ b/modules/openapi-generator-maven-plugin/src/main/java/org/openapitools/codegen/plugin/CodeGenMojo.java @@ -70,7 +70,7 @@ import com.google.common.io.Files; * Goal which generates client/server code from a OpenAPI json/yaml definition. */ @SuppressWarnings({"unused", "MismatchedQueryAndUpdateOfCollection"}) -@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES) +@Mojo(name = "generate", defaultPhase = LifecyclePhase.GENERATE_SOURCES, threadSafe = true) public class CodeGenMojo extends AbstractMojo { private static final Logger LOGGER = LoggerFactory.getLogger(CodeGenMojo.class); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java index a60f824278b..840790ed4c8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/config/CodegenConfigurator.java @@ -79,69 +79,74 @@ public class CodegenConfigurator { public static CodegenConfigurator fromFile(String configFile, Module... modules) { if (isNotEmpty(configFile)) { - ObjectMapper mapper; + DynamicSettings settings = readDynamicSettings(configFile, modules); - if (FilenameUtils.isExtension(configFile, new String[]{"yml", "yaml"})) { - mapper = Yaml.mapper(); - } else { - mapper = Json.mapper(); + CodegenConfigurator configurator = new CodegenConfigurator(); + + GeneratorSettings generatorSettings = settings.getGeneratorSettings(); + WorkflowSettings workflowSettings = settings.getWorkflowSettings(); + + // We copy "cached" properties into configurator so it is appropriately configured with all settings in external files. + // FIXME: target is to eventually move away from CodegenConfigurator properties except gen/workflow settings. + configurator.generatorName = generatorSettings.getGeneratorName(); + configurator.inputSpec = workflowSettings.getInputSpec(); + configurator.templatingEngineName = workflowSettings.getTemplatingEngineName(); + if (workflowSettings.getSystemProperties() != null) { + configurator.systemProperties.putAll(workflowSettings.getSystemProperties()); + } + if(generatorSettings.getInstantiationTypes() != null) { + configurator.instantiationTypes.putAll(generatorSettings.getInstantiationTypes()); + } + if(generatorSettings.getTypeMappings() != null) { + configurator.typeMappings.putAll(generatorSettings.getTypeMappings()); + } + if(generatorSettings.getAdditionalProperties() != null) { + configurator.additionalProperties.putAll(generatorSettings.getAdditionalProperties()); + } + if(generatorSettings.getImportMappings() != null) { + configurator.importMappings.putAll(generatorSettings.getImportMappings()); + } + if(generatorSettings.getLanguageSpecificPrimitives() != null) { + configurator.languageSpecificPrimitives.addAll(generatorSettings.getLanguageSpecificPrimitives()); + } + if(generatorSettings.getReservedWordMappings() != null) { + configurator.reservedWordMappings.putAll(generatorSettings.getReservedWordMappings()); + } + if(generatorSettings.getServerVariables() != null) { + configurator.serverVariables.putAll(generatorSettings.getServerVariables()); } - if (modules != null && modules.length > 0) { - mapper.registerModules(modules); - } + configurator.generatorSettingsBuilder = GeneratorSettings.newBuilder(generatorSettings); + configurator.workflowSettingsBuilder = WorkflowSettings.newBuilder(workflowSettings); - mapper.registerModule(new GuavaModule()); - - try { - DynamicSettings settings = mapper.readValue(new File(configFile), DynamicSettings.class); - CodegenConfigurator configurator = new CodegenConfigurator(); - - GeneratorSettings generatorSettings = settings.getGeneratorSettings(); - WorkflowSettings workflowSettings = settings.getWorkflowSettings(); - - // We copy "cached" properties into configurator so it is appropriately configured with all settings in external files. - // FIXME: target is to eventually move away from CodegenConfigurator properties except gen/workflow settings. - configurator.generatorName = generatorSettings.getGeneratorName(); - configurator.inputSpec = workflowSettings.getInputSpec(); - configurator.templatingEngineName = workflowSettings.getTemplatingEngineName(); - if (workflowSettings.getSystemProperties() != null) { - configurator.systemProperties.putAll(workflowSettings.getSystemProperties()); - } - if(generatorSettings.getInstantiationTypes() != null) { - configurator.instantiationTypes.putAll(generatorSettings.getInstantiationTypes()); - } - if(generatorSettings.getTypeMappings() != null) { - configurator.typeMappings.putAll(generatorSettings.getTypeMappings()); - } - if(generatorSettings.getAdditionalProperties() != null) { - configurator.additionalProperties.putAll(generatorSettings.getAdditionalProperties()); - } - if(generatorSettings.getImportMappings() != null) { - configurator.importMappings.putAll(generatorSettings.getImportMappings()); - } - if(generatorSettings.getLanguageSpecificPrimitives() != null) { - configurator.languageSpecificPrimitives.addAll(generatorSettings.getLanguageSpecificPrimitives()); - } - if(generatorSettings.getReservedWordMappings() != null) { - configurator.reservedWordMappings.putAll(generatorSettings.getReservedWordMappings()); - } - if(generatorSettings.getServerVariables() != null) { - configurator.serverVariables.putAll(generatorSettings.getServerVariables()); - } - - configurator.generatorSettingsBuilder = GeneratorSettings.newBuilder(generatorSettings); - configurator.workflowSettingsBuilder = WorkflowSettings.newBuilder(workflowSettings); - - return configurator; - } catch (IOException ex) { - LOGGER.error(ex.getMessage()); - throw new RuntimeException("Unable to deserialize config file: " + configFile); - } + return configurator; } return null; } + private static DynamicSettings readDynamicSettings(String configFile, Module... modules) { + ObjectMapper mapper; + + if (FilenameUtils.isExtension(configFile.toLowerCase(Locale.ROOT), new String[]{"yml", "yaml"})) { + mapper = Yaml.mapper().copy(); + } else { + mapper = Json.mapper().copy(); + } + + if (modules != null && modules.length > 0) { + mapper.registerModules(modules); + } + + mapper.registerModule(new GuavaModule()); + + try { + return mapper.readValue(new File(configFile), DynamicSettings.class); + } catch (IOException ex) { + LOGGER.error(ex.getMessage()); + throw new RuntimeException("Unable to deserialize config file: " + configFile); + } + } + public CodegenConfigurator addServerVariable(String key, String value) { this.serverVariables.put(key, value); generatorSettingsBuilder.withServerVariable(key, value); From a8620b86638644a4da489f875fde5f62b2e8aa48 Mon Sep 17 00:00:00 2001 From: William Cheng Date: Sun, 19 Apr 2020 10:46:34 +0800 Subject: [PATCH 06/21] add bearer support to csharp client (#5975) --- .../src/main/resources/csharp/README.mustache | 12 ++++++++++++ .../src/main/resources/csharp/api.mustache | 18 ++++++++++++++++++ .../src/main/resources/csharp/api_doc.mustache | 6 ++++++ .../src/Org.OpenAPITools/Model/FormatTest.cs | 16 +++++++++++++++- .../src/Org.OpenAPITools/Model/FormatTest.cs | 16 +++++++++++++++- 5 files changed, 66 insertions(+), 2 deletions(-) diff --git a/modules/openapi-generator/src/main/resources/csharp/README.mustache b/modules/openapi-generator/src/main/resources/csharp/README.mustache index 474bfe829b4..da6053f4aa2 100644 --- a/modules/openapi-generator/src/main/resources/csharp/README.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/README.mustache @@ -119,9 +119,15 @@ namespace Example {{#hasAuthMethods}} {{#authMethods}} {{#isBasic}} + {{#isBasicBasic}} // Configure HTTP basic authorization: {{{name}}} Configuration.Default.Username = "YOUR_USERNAME"; Configuration.Default.Password = "YOUR_PASSWORD"; + {{/isBasicBasic}} + {{#isBasicBearer}} + // Configure HTTP bearer authorization: {{{name}}} + Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN"; + {{/isBasicBearer}} {{/isBasic}} {{#isApiKey}} // Configure API key authorization: {{{name}}} @@ -205,8 +211,14 @@ Authentication schemes defined for the API: - **Location**: {{#isKeyInQuery}}URL query string{{/isKeyInQuery}}{{#isKeyInHeader}}HTTP header{{/isKeyInHeader}} {{/isApiKey}} {{#isBasic}} +{{#isBasicBasic}} - **Type**: HTTP basic authentication +{{/isBasicBasic}} +{{#isBasicBearer}} + +- **Type**: HTTP bearer authentication +{{/isBasicBearer}} {{/isBasic}} {{#isOAuth}} diff --git a/modules/openapi-generator/src/main/resources/csharp/api.mustache b/modules/openapi-generator/src/main/resources/csharp/api.mustache index f040c439025..a0300971694 100644 --- a/modules/openapi-generator/src/main/resources/csharp/api.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/api.mustache @@ -278,11 +278,20 @@ namespace {{packageName}}.{{apiPackage}} {{/isKeyInQuery}} {{/isApiKey}} {{#isBasic}} + {{#isBasicBasic}} // http basic authentication required if (!String.IsNullOrEmpty(this.Configuration.Username) || !String.IsNullOrEmpty(this.Configuration.Password)) { localVarHeaderParams["Authorization"] = "Basic " + ApiClient.Base64Encode(this.Configuration.Username + ":" + this.Configuration.Password); } + {{/isBasicBasic}} + {{#isBasicBearer}} + // http beerer authentication required + if (!String.IsNullOrEmpty(this.Configuration.AccessToken)) + { + localVarHeaderParams["Authorization"] = "Bearer " + this.Configuration.AccessToken; + } + {{/isBasicBearer}} {{/isBasic}} {{#isOAuth}} // oauth required @@ -414,11 +423,20 @@ namespace {{packageName}}.{{apiPackage}} {{/isKeyInQuery}} {{/isApiKey}} {{#isBasic}} + {{#isBasicBasic}} // http basic authentication required if (!String.IsNullOrEmpty(this.Configuration.Username) || !String.IsNullOrEmpty(this.Configuration.Password)) { localVarHeaderParams["Authorization"] = "Basic " + ApiClient.Base64Encode(this.Configuration.Username + ":" + this.Configuration.Password); } + {{/isBasicBasic}} + {{#isBasicBearer}} + // http bearer authentication required + if (!String.IsNullOrEmpty(this.Configuration.AccessToken)) + { + localVarHeaderParams["Authorization"] = "Bearer " + this.Configuration.AccessToken; + } + {{/isBasicBearer}} {{/isBasic}} {{#isOAuth}} // oauth required diff --git a/modules/openapi-generator/src/main/resources/csharp/api_doc.mustache b/modules/openapi-generator/src/main/resources/csharp/api_doc.mustache index df59f42415c..6e4bbf7c9a4 100644 --- a/modules/openapi-generator/src/main/resources/csharp/api_doc.mustache +++ b/modules/openapi-generator/src/main/resources/csharp/api_doc.mustache @@ -39,9 +39,15 @@ namespace Example {{#hasAuthMethods}} {{#authMethods}} {{#isBasic}} + {{#isBasicBasic}} // Configure HTTP basic authorization: {{{name}}} Configuration.Default.Username = "YOUR_USERNAME"; Configuration.Default.Password = "YOUR_PASSWORD"; + {{/isBasicBasic}} + {{#isBasicBearer}} + // Configure HTTP bearer authorization: {{{name}}} + Configuration.Default.AccessToken = "YOUR_ACCESS_TOKEN"; + {{/isBasicBearer}} {{/isBasic}} {{#isApiKey}} // Configure API key authorization: {{{name}}} diff --git a/samples/client/petstore/csharp/OpenAPIClientNet40/src/Org.OpenAPITools/Model/FormatTest.cs b/samples/client/petstore/csharp/OpenAPIClientNet40/src/Org.OpenAPITools/Model/FormatTest.cs index 31193ac3960..eedd4b6236e 100644 --- a/samples/client/petstore/csharp/OpenAPIClientNet40/src/Org.OpenAPITools/Model/FormatTest.cs +++ b/samples/client/petstore/csharp/OpenAPIClientNet40/src/Org.OpenAPITools/Model/FormatTest.cs @@ -367,6 +367,8 @@ namespace Org.OpenAPITools.Model /// Validation Result IEnumerable IValidatableObject.Validate(ValidationContext validationContext) { + + // Integer (int) maximum if(this.Integer > (int)100) { @@ -379,6 +381,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Integer, must be a value greater than or equal to 10.", new [] { "Integer" }); } + + // Int32 (int) maximum if(this.Int32 > (int)200) { @@ -391,6 +395,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Int32, must be a value greater than or equal to 20.", new [] { "Int32" }); } + + // Number (decimal) maximum if(this.Number > (decimal)543.2) { @@ -403,6 +409,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Number, must be a value greater than or equal to 32.1.", new [] { "Number" }); } + + // Float (float) maximum if(this.Float > (float)987.6) { @@ -415,6 +423,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Float, must be a value greater than or equal to 54.3.", new [] { "Float" }); } + + // Double (double) maximum if(this.Double > (double)123.4) { @@ -427,6 +437,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Double, must be a value greater than or equal to 67.8.", new [] { "Double" }); } + + // String (string) pattern Regex regexString = new Regex(@"[a-z]", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); if (false == regexString.Match(this.String).Success) @@ -434,6 +446,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for String, must match a pattern of " + regexString, new [] { "String" }); } + + // Password (string) maxLength if(this.Password != null && this.Password.Length > 64) { @@ -445,7 +459,7 @@ namespace Org.OpenAPITools.Model { yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Password, length must be greater than 10.", new [] { "Password" }); } - + yield break; } } diff --git a/samples/client/petstore/csharp/OpenAPIClientWithPropertyChanged/src/Org.OpenAPITools/Model/FormatTest.cs b/samples/client/petstore/csharp/OpenAPIClientWithPropertyChanged/src/Org.OpenAPITools/Model/FormatTest.cs index d8452eb07cb..b3ebc9f373b 100644 --- a/samples/client/petstore/csharp/OpenAPIClientWithPropertyChanged/src/Org.OpenAPITools/Model/FormatTest.cs +++ b/samples/client/petstore/csharp/OpenAPIClientWithPropertyChanged/src/Org.OpenAPITools/Model/FormatTest.cs @@ -390,6 +390,8 @@ namespace Org.OpenAPITools.Model /// Validation Result IEnumerable IValidatableObject.Validate(ValidationContext validationContext) { + + // Integer (int) maximum if(this.Integer > (int)100) { @@ -402,6 +404,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Integer, must be a value greater than or equal to 10.", new [] { "Integer" }); } + + // Int32 (int) maximum if(this.Int32 > (int)200) { @@ -414,6 +418,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Int32, must be a value greater than or equal to 20.", new [] { "Int32" }); } + + // Number (decimal) maximum if(this.Number > (decimal)543.2) { @@ -426,6 +432,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Number, must be a value greater than or equal to 32.1.", new [] { "Number" }); } + + // Float (float) maximum if(this.Float > (float)987.6) { @@ -438,6 +446,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Float, must be a value greater than or equal to 54.3.", new [] { "Float" }); } + + // Double (double) maximum if(this.Double > (double)123.4) { @@ -450,6 +460,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Double, must be a value greater than or equal to 67.8.", new [] { "Double" }); } + + // String (string) pattern Regex regexString = new Regex(@"[a-z]", RegexOptions.CultureInvariant | RegexOptions.IgnoreCase); if (false == regexString.Match(this.String).Success) @@ -457,6 +469,8 @@ namespace Org.OpenAPITools.Model yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for String, must match a pattern of " + regexString, new [] { "String" }); } + + // Password (string) maxLength if(this.Password != null && this.Password.Length > 64) { @@ -468,7 +482,7 @@ namespace Org.OpenAPITools.Model { yield return new System.ComponentModel.DataAnnotations.ValidationResult("Invalid value for Password, length must be greater than 10.", new [] { "Password" }); } - + yield break; } } From 171f71872e7cc7cea32df21f504bdc7676f1f1d7 Mon Sep 17 00:00:00 2001 From: William Cheng Date: Sun, 19 Apr 2020 12:37:48 +0800 Subject: [PATCH 07/21] add test to reuse object from the server (#5976) --- .../src/PSPetstore/PSPetstore.psd1 | 2 +- .../tests/Petstore.Tests.ps1 | 13 +++++++++++++ 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/samples/client/petstore/powershell-experimental/src/PSPetstore/PSPetstore.psd1 b/samples/client/petstore/powershell-experimental/src/PSPetstore/PSPetstore.psd1 index 726f4ea5111..5697624e593 100644 --- a/samples/client/petstore/powershell-experimental/src/PSPetstore/PSPetstore.psd1 +++ b/samples/client/petstore/powershell-experimental/src/PSPetstore/PSPetstore.psd1 @@ -3,7 +3,7 @@ # # Generated by: OpenAPI Generator Team # -# Generated on: 4/10/20 +# Generated on: 4/19/20 # @{ diff --git a/samples/client/petstore/powershell-experimental/tests/Petstore.Tests.ps1 b/samples/client/petstore/powershell-experimental/tests/Petstore.Tests.ps1 index adf55dc4bfe..c0c01a1274b 100644 --- a/samples/client/petstore/powershell-experimental/tests/Petstore.Tests.ps1 +++ b/samples/client/petstore/powershell-experimental/tests/Petstore.Tests.ps1 @@ -63,8 +63,21 @@ Describe -tag 'PSOpenAPITools' -name 'Integration Tests' { $file = Get-Item "./plus.gif" #$Result = Invoke-PSUploadFile -petId $Id -additionalMetadata "Additional data" -File $file + # modify and update + # + $NewPet = $Result["response"] + + $NewPet."id" = $NewPet."id" + 1 + $NewPet."name" = $NewPet."name" + "PowerShell Modify" + + $Result = Update-PSPet -Pet $NewPet + $Result = Get-PSPetById -petId $NewPet."id" -WithHttpInfo + $Result["Response"]."id" | Should Be $NewPet."id" + $Result["Response"]."name" | Should Be $NewPet."name" + # Delete $Result = Remove-Pet -petId $Id + $Result = Remove-Pet -petId $NewPet."id" } From f6572fd2f4874f83d3d6faf38a8231d873f3c019 Mon Sep 17 00:00:00 2001 From: "zaleski.d" Date: Sun, 19 Apr 2020 15:38:28 +0200 Subject: [PATCH 08/21] [bug][html2] Fix visibility of body/response schemas (#5643) * 1441 fix visibility of body/response schemas * Handle schemas with array items * Point to template directory in bin script * Regenerate sample Co-authored-by: Jim Schubert --- bin/html2-petstore.sh | 2 +- .../openapitools/codegen/DefaultCodegen.java | 7 + .../main/resources/htmlDocs2/index.mustache | 35 +- .../main/resources/htmlDocs2/paramB.mustache | 5 +- .../html2/.openapi-generator/VERSION | 2 +- samples/documentation/html2/index.html | 664 ++++++++++++------ 6 files changed, 475 insertions(+), 240 deletions(-) diff --git a/bin/html2-petstore.sh b/bin/html2-petstore.sh index 3b82165d103..d125551e133 100755 --- a/bin/html2-petstore.sh +++ b/bin/html2-petstore.sh @@ -27,6 +27,6 @@ fi # if you've executed sbt assembly previously it will use that instead. export JAVA_OPTS="${JAVA_OPTS} -Xmx1024M -DloggerPath=conf/log4j.properties" -ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g html2 -o samples/documentation/html2 --additional-properties hideGenerationTimestamp=true $@" +ags="generate -i modules/openapi-generator/src/test/resources/2_0/petstore.yaml -g html2 -o samples/documentation/html2 -t modules/openapi-generator/src/main/resources/htmlDocs2/ --additional-properties hideGenerationTimestamp=true $@" java $JAVA_OPTS -jar $executable $ags 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 d75476aa29a..e6a75981b7f 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 @@ -5543,6 +5543,8 @@ public class DefaultCodegen implements CodegenConfig { setParameterNullable(codegenParameter, codegenProperty); } + addJsonSchemaForBodyRequestInCaseItsNotPresent(codegenParameter, body); + // set the parameter's example value // should be overridden by lang codegen setParameterExampleValue(codegenParameter, body); @@ -5550,6 +5552,11 @@ public class DefaultCodegen implements CodegenConfig { return codegenParameter; } + private void addJsonSchemaForBodyRequestInCaseItsNotPresent(CodegenParameter codegenParameter, RequestBody body){ + if(codegenParameter.jsonSchema == null) + codegenParameter.jsonSchema = Json.pretty(body); + } + protected void addOption(String key, String description, String defaultValue) { CliOption option = new CliOption(key, description); if (defaultValue != null) diff --git a/modules/openapi-generator/src/main/resources/htmlDocs2/index.mustache b/modules/openapi-generator/src/main/resources/htmlDocs2/index.mustache index 1cb04a58a9f..e82cd10725d 100644 --- a/modules/openapi-generator/src/main/resources/htmlDocs2/index.mustache +++ b/modules/openapi-generator/src/main/resources/htmlDocs2/index.mustache @@ -101,6 +101,31 @@ //Convert elements with "marked" class to markdown processMarked(); }); + + function findNode(id, currentNode) { + return (Object.keys(currentNode)[0] === id) ? currentNode : findNodeInChildren(id, currentNode); + } + + function findNodeInChildren(id, currentNode) { + for (let prop in currentNode) { + if (currentNode.hasOwnProperty(prop)) { + let currentChild = currentNode[prop]; + if (id === prop) { + return currentChild; + } else { + // Search in the current child + if (typeof (currentChild) === 'object') { + let result = findNode(id, currentChild); + if (result !== false) { + return result; + } + } + } + } + } + return false; + } +