From 985e8e0066e767efcb0aa1833facf6d387d62ca9 Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Wed, 1 May 2019 14:37:27 -0400 Subject: [PATCH 1/3] [all] Adds strict spec option Introduces an option to allow user customization of strict specification behaviors. For instance, OpenAPI 3.x requires a path object name to be prefixed with '/' so we append any missing '/', but this may not be desirable to some users or generators. In this commit, this fix specifically is the only modification affected. --- .../openapitools/codegen/cmd/Generate.java | 11 +++++++ .../codegen/cmd/GenerateTest.java | 20 ++++++++++++ .../openapi-generator-maven-plugin/README.md | 1 + .../codegen/plugin/CodeGenMojo.java | 10 ++++++ .../openapitools/codegen/CodegenConfig.java | 4 +++ .../openapitools/codegen/DefaultCodegen.java | 31 +++++++++++++++++-- .../codegen/config/CodegenConfigurator.java | 11 +++++++ .../codegen/DefaultGeneratorTest.java | 30 +++++++++++++++++- 8 files changed, 114 insertions(+), 4 deletions(-) diff --git a/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java b/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java index 11c0834ddc4f..20ea0ceb4f45 100644 --- a/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java +++ b/modules/openapi-generator-cli/src/main/java/org/openapitools/codegen/cmd/Generate.java @@ -214,6 +214,12 @@ public class Generate implements Runnable { description = "Skips the default behavior of validating an input specification.") private Boolean skipValidateSpec; + @Option(name = {"--strict-spec"}, + title = "true/false strict behavior", + description = "'MUST' and 'SHALL' wording in OpenAPI spec is strictly adhered to, e.g. no fixes will be applied to documents which pass validation but don't follow the spec.", + arity = 1) + private Boolean strictSpecBehavior; + @Option(name = {"--log-to-stderr"}, title = "Log to STDERR", description = "write all log messages (not just errors) to STDOUT." @@ -368,10 +374,15 @@ public void run() { if (generateAliasAsModel != null) { configurator.setGenerateAliasAsModel(generateAliasAsModel); } + if (minimalUpdate != null) { configurator.setEnableMinimalUpdate(minimalUpdate); } + if (strictSpecBehavior != null) { + configurator.setStrictSpecBehavior(strictSpecBehavior); + } + applySystemPropertiesKvpList(systemProperties, configurator); applyInstantiationTypesKvpList(instantiationTypes, configurator); applyImportMappingsKvpList(importMappings, configurator); diff --git a/modules/openapi-generator-cli/src/test/java/org/openapitools/codegen/cmd/GenerateTest.java b/modules/openapi-generator-cli/src/test/java/org/openapitools/codegen/cmd/GenerateTest.java index 882424341c65..d8812b5c8d1f 100644 --- a/modules/openapi-generator-cli/src/test/java/org/openapitools/codegen/cmd/GenerateTest.java +++ b/modules/openapi-generator-cli/src/test/java/org/openapitools/codegen/cmd/GenerateTest.java @@ -277,6 +277,26 @@ public void testSkipOverwrite() throws Exception { }; } + @Test + public void testStrictSpec() throws Exception { + + setupAndRunGenericTest("--strict-spec", "true"); + new FullVerifications() { + { + configurator.setStrictSpecBehavior(true); + times = 1; + } + }; + + setupAndRunGenericTest("--strict-spec", "false"); + new FullVerifications() { + { + configurator.setStrictSpecBehavior(false); + times = 1; + } + }; + } + @Test public void testPackageName() throws Exception { final String value = "io.foo.bar.baz"; diff --git a/modules/openapi-generator-maven-plugin/README.md b/modules/openapi-generator-maven-plugin/README.md index 1489b1f2b287..ec58cafc57a5 100644 --- a/modules/openapi-generator-maven-plugin/README.md +++ b/modules/openapi-generator-maven-plugin/README.md @@ -57,6 +57,7 @@ mvn clean compile - `logToStderr` - write all log messages (not just errors) to STDOUT - `enablePostProcessFile` - enable file post-processing hook - `skipValidateSpec` - Whether or not to skip validating the input spec prior to generation. By default, invalid specifications will result in an error. +- `strictSpec` - Whether or not to treat an input document strictly against the spec. 'MUST' and 'SHALL' wording in OpenAPI spec is strictly adhered to, e.g. no fixes will be applied to documents which pass validation but don't follow the spec. - `generateAliasAsModel` - generate alias (array, map) as model - `generateApis` - generate the apis (`true` by default) - `generateApiTests` - generate the api tests (`true` by default. Only available if `generateApis` is `true`) 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 10521857535c..791c83014181 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 @@ -235,6 +235,12 @@ public class CodeGenMojo extends AbstractMojo { @Parameter(name = "skipValidateSpec", required = false) private Boolean skipValidateSpec; + /** + * To treat a document strictly against the spec. + */ + @Parameter(name = "strictSpec", required = false) + private Boolean strictSpecBehavior; + /** * To generate alias (array, map) as model */ @@ -459,6 +465,10 @@ public void execute() throws MojoExecutionException { configurator.setValidateSpec(!skipValidateSpec); } + if (strictSpecBehavior != null) { + configurator.setStrictSpecBehavior(strictSpecBehavior); + } + if (logToStderr != null) { configurator.setLogToStderr(logToStderr); } diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java index 4ebbdf5c6370..137676771eb1 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenConfig.java @@ -270,4 +270,8 @@ public interface CodegenConfig { public boolean isEnableMinimalUpdate(); public void setEnableMinimalUpdate(boolean isEnableMinimalUpdate); + + boolean isStrictSpecBehavior(); + + void setStrictSpecBehavior(boolean strictSpecBehavior); } 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 5f7693a97108..4c45be94b17d 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 @@ -118,6 +118,9 @@ public class DefaultCodegen implements CodegenConfig { // flag to indicate whether to only update files whose contents have changed protected boolean enableMinimalUpdate = false; + // acts strictly upon a spec, potentially modifying it to have consistent behavior across generators. + protected boolean strictSpecBehavior = true; + // make openapi available to all methods protected OpenAPI openAPI; @@ -2387,11 +2390,13 @@ public CodegenOperation fromOperation(String path, } operationId = removeNonNameElementToCamelCase(operationId); - if (path.startsWith("/")) { - op.path = path; - } else { + if (isStrictSpecBehavior() && !path.startsWith("/")) { + // modifies an operation.path to strictly conform to OpenAPI Spec op.path = "/" + path; + } else { + op.path = path; } + op.operationId = toOperationId(operationId); op.summary = escapeText(operation.getSummary()); op.unescapedNotes = operation.getDescription(); @@ -4900,4 +4905,24 @@ public void setEnableMinimalUpdate(boolean enableMinimalUpdate) { this.enableMinimalUpdate = enableMinimalUpdate; } + /** + * Indicates whether the codegen configuration should treat documents as strictly defined by the OpenAPI specification. + * + * @return true to act strictly upon spec documents, potentially modifying the spec to strictly fit the spec. + */ + @Override + public boolean isStrictSpecBehavior() { + return this.strictSpecBehavior; + } + + /** + * Sets the boolean valid indicating whether generation will work strictly against the specification, potentially making + * minor changes to the input document. + * + * @param strictSpecBehavior true if we will behave strictly, false to allow specification documents which pass validation to be loosely interpreted against the spec. + */ + @Override + public void setStrictSpecBehavior(final boolean strictSpecBehavior) { + this.strictSpecBehavior = strictSpecBehavior; + } } 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 0e8269987ba9..aea78d7a6961 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 @@ -85,6 +85,7 @@ public class CodegenConfigurator implements Serializable { private boolean validateSpec; private boolean enablePostProcessFile; private boolean enableMinimalUpdate; + private boolean strictSpecBehavior; private String templateDir; private String templatingEngineName; private String auth; @@ -117,6 +118,7 @@ public class CodegenConfigurator implements Serializable { public CodegenConfigurator() { this.validateSpec = true; + this.strictSpecBehavior = true; this.setOutputDir("."); } @@ -252,6 +254,15 @@ public CodegenConfigurator setModelNameSuffix(String suffix) { return this; } + public boolean isStrictSpecBehavior() { + return strictSpecBehavior; + } + + public CodegenConfigurator setStrictSpecBehavior(boolean strictSpecBehavior) { + this.strictSpecBehavior = strictSpecBehavior; + return this; + } + public boolean isVerbose() { return verbose; } diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java index be1c745fe4ae..89ebd814187c 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/DefaultGeneratorTest.java @@ -48,7 +48,35 @@ public void testProcessPaths() throws Exception { Assert.assertEquals(defaultList.get(3).path, "/path4"); Assert.assertEquals(defaultList.get(3).allParams.size(), 1); } - + + + @Test + public void testNonStrictProcessPaths() throws Exception { + OpenAPI openAPI = TestUtils.createOpenAPI(); + openAPI.setPaths(new Paths()); + openAPI.getPaths().addPathItem("path1/", new PathItem().get(new Operation().operationId("op1").responses(new ApiResponses().addApiResponse("201", new ApiResponse().description("OK"))))); + openAPI.getPaths().addPathItem("path2/", new PathItem().get(new Operation().operationId("op2").addParametersItem(new QueryParameter().name("p1").schema(new StringSchema())).responses(new ApiResponses().addApiResponse("201", new ApiResponse().description("OK"))))); + + ClientOptInput opts = new ClientOptInput(); + opts.setOpenAPI(openAPI); + CodegenConfig config = new DefaultCodegen(); + config.setStrictSpecBehavior(false); + opts.setConfig(config); + opts.setOpts(new ClientOpts()); + + DefaultGenerator generator = new DefaultGenerator(); + generator.opts(opts); + Map> result = generator.processPaths(openAPI.getPaths()); + Assert.assertEquals(result.size(), 1); + List defaultList = result.get("Default"); + Assert.assertEquals(defaultList.size(), 2); + Assert.assertEquals(defaultList.get(0).path, "path1/"); + Assert.assertEquals(defaultList.get(0).allParams.size(), 0); + Assert.assertEquals(defaultList.get(1).path, "path2/"); + Assert.assertEquals(defaultList.get(1).allParams.size(), 1); + } + + @Test public void minimalUpdateTest() throws IOException { OpenAPI openAPI = TestUtils.createOpenAPI(); From f1749f801ebcbce080fe400842fd1dd4781c39b6 Mon Sep 17 00:00:00 2001 From: Jim Schubert Date: Wed, 1 May 2019 16:14:21 -0400 Subject: [PATCH 2/3] Clarify strict-spec docs, add option to README.md --- README.md | 1 + .../src/main/java/org/openapitools/codegen/cmd/Generate.java | 2 +- modules/openapi-generator-maven-plugin/README.md | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 4b4548a2e49a..9f4bc162012c 100644 --- a/README.md +++ b/README.md @@ -447,6 +447,7 @@ SYNOPSIS [--remove-operation-id-prefix] [--reserved-words-mappings ...] [(-s | --skip-overwrite)] [--skip-validate-spec] + [--strict-spec ] [(-t