From fd3b883e80b30de2f459ab220d9138cb1c453d52 Mon Sep 17 00:00:00 2001 From: Arthur Mogliev Date: Tue, 8 May 2018 15:46:23 +0400 Subject: [PATCH] [DefaultCodegen] Fill CodegenOperation::produces with unique media types (#343) --- .../openapitools/codegen/DefaultCodegen.java | 63 ++++++++----------- .../codegen/languages/AbstractAdaCodegen.java | 29 ++++++--- .../codegen/languages/ApexClientCodegen.java | 32 +++++----- .../languages/CppPistacheServerCodegen.java | 29 +++++---- .../languages/CppRestClientCodegen.java | 28 ++++----- .../codegen/utils/ModelUtils.java | 30 +++++++-- .../codegen/DefaultCodegenTest.java | 16 ++++- .../src/test/resources/3_0/two-responses.yaml | 29 +++++++++ 8 files changed, 163 insertions(+), 93 deletions(-) create mode 100644 modules/openapi-generator/src/test/resources/3_0/two-responses.yaml 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 7b04235dfe9..80e25e5a8e7 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 @@ -27,8 +27,6 @@ import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.headers.Header; import io.swagger.v3.oas.models.media.ArraySchema; import io.swagger.v3.oas.models.media.ComposedSchema; -import io.swagger.v3.oas.models.media.Content; -import io.swagger.v3.oas.models.media.MediaType; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.media.StringSchema; import io.swagger.v3.oas.models.parameters.CookieParameter; @@ -2142,7 +2140,7 @@ public class DefaultCodegen implements CodegenConfig { op.responses.get(op.responses.size() - 1).hasMore = false; if (methodResponse != null) { - final Schema responseSchema = getSchemaFromResponse(methodResponse); + final Schema responseSchema = ModelUtils.getSchemaFromResponse(methodResponse); if (responseSchema != null) { CodegenProperty cm = fromProperty("response", responseSchema); @@ -2386,7 +2384,7 @@ public class DefaultCodegen implements CodegenConfig { } else { r.code = responseCode; } - final Schema responseSchema = getSchemaFromResponse(response); + final Schema responseSchema = ModelUtils.getSchemaFromResponse(response); r.schema = responseSchema; r.message = escapeText(response.getDescription()); // TODO need to revise and test examples in responses @@ -3819,22 +3817,6 @@ public class DefaultCodegen implements CodegenConfig { return new ArrayList<>(requestBody.getContent().keySet()).get(0); } - protected Schema getSchemaFromBody(RequestBody requestBody) { - return getSchemaFromContent(requestBody.getContent()); - } - - protected Schema getSchemaFromResponse(ApiResponse response) { - return getSchemaFromContent(response.getContent()); - } - - private Schema getSchemaFromContent(Content content) { - if (content == null || content.isEmpty()) { - return null; - } - MediaType mediaType = content.values().iterator().next(); - return mediaType.getSchema(); - } - protected Parameter getParameterFromRef(String ref, OpenAPI openAPI) { String parameterName = ref.substring(ref.lastIndexOf('/') + 1); Map parameterMap = openAPI.getComponents().getParameters(); @@ -3944,7 +3926,7 @@ public class DefaultCodegen implements CodegenConfig { return false; } - Schema schema = getSchemaFromBody(requestBody); + Schema schema = ModelUtils.getSchemaFromRequestBody(requestBody); return ModelUtils.getReferencedSchema(openAPI, schema) != null; } @@ -3959,25 +3941,30 @@ public class DefaultCodegen implements CodegenConfig { codegenOperation.produces = new ArrayList<>(); } + Set existingMediaTypes = new HashSet<>(); + for (Map mediaType: codegenOperation.produces) { + existingMediaTypes.add(mediaType.get("mediaType")); + } + int count = 0; for (String key : produces) { - Map mediaType = new HashMap(); - // escape quotation to avoid code injection - if ("*/*".equals(key)) { // "*/*" is a special case, do nothing - mediaType.put("mediaType", key); - } else { - mediaType.put("mediaType", escapeText(escapeQuotationMark(key))); - } + // escape quotation to avoid code injection, "*/*" is a special case, do nothing + String encodedKey = "*/*".equals(key)? key : escapeText(escapeQuotationMark(key)); + //Only unique media types should be added to "produces" + if (!existingMediaTypes.contains(encodedKey)) { + Map mediaType = new HashMap(); + mediaType.put("mediaType", encodedKey); - count += 1; - if (count < produces.size()) { - mediaType.put("hasMore", "true"); - } else { - mediaType.put("hasMore", null); - } + count += 1; + if (count < produces.size()) { + mediaType.put("hasMore", "true"); + } else { + mediaType.put("hasMore", null); + } - codegenOperation.produces.add(mediaType); - codegenOperation.hasProduces = Boolean.TRUE; + codegenOperation.produces.add(mediaType); + codegenOperation.hasProduces = Boolean.TRUE; + } } } @@ -4075,7 +4062,7 @@ public class DefaultCodegen implements CodegenConfig { public List fromRequestBodyToFormParameters(RequestBody body, Map schemas, Set imports) { List parameters = new ArrayList(); LOGGER.debug("debugging fromRequestBodyToFormParameters= " + body); - Schema schema = getSchemaFromBody(body); + Schema schema = ModelUtils.getSchemaFromRequestBody(body); if (StringUtils.isNotBlank(schema.get$ref())) { schema = schemas.get(getSimpleRef(schema.get$ref())); } @@ -4229,7 +4216,7 @@ public class DefaultCodegen implements CodegenConfig { String name = null; LOGGER.debug("Request body = " + body); - Schema schema = getSchemaFromBody(body); + Schema schema = ModelUtils.getSchemaFromRequestBody(body); if (StringUtils.isNotBlank(schema.get$ref())) { name = getSimpleRef(schema.get$ref()); schema = schemas.get(name); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractAdaCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractAdaCodegen.java index b0898a25881..892ddd29b7f 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractAdaCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/AbstractAdaCodegen.java @@ -17,22 +17,31 @@ package org.openapitools.codegen.languages; -import com.fasterxml.jackson.core.JsonProcessingException; import com.samskivert.mustache.Escapers; import com.samskivert.mustache.Mustache; -import io.swagger.v3.oas.models.responses.ApiResponse; -import org.openapitools.codegen.*; -import org.openapitools.codegen.utils.ModelUtils; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.media.*; -import io.swagger.v3.oas.models.parameters.*; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.responses.ApiResponse; -import io.swagger.v3.core.util.Json; +import org.openapitools.codegen.CodegenConfig; +import org.openapitools.codegen.CodegenConstants; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; +import org.openapitools.codegen.CodegenSecurity; +import org.openapitools.codegen.DefaultCodegen; +import org.openapitools.codegen.utils.ModelUtils; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; abstract public class AbstractAdaCodegen extends DefaultCodegen implements CodegenConfig { protected String packageName = "defaultPackage"; @@ -397,8 +406,8 @@ abstract public class AbstractAdaCodegen extends DefaultCodegen implements Codeg if (operation.getResponses() != null && !operation.getResponses().isEmpty()) { ApiResponse methodResponse = findMethodResponse(operation.getResponses()); - if (methodResponse != null && getSchemaFromResponse(methodResponse) != null) { - CodegenProperty cm = fromProperty("response", getSchemaFromResponse(methodResponse)); + if (methodResponse != null && ModelUtils.getSchemaFromResponse(methodResponse) != null) { + CodegenProperty cm = fromProperty("response", ModelUtils.getSchemaFromResponse(methodResponse)); op.vendorExtensions.put("x-codegen-response", cm); if ("HttpContent".equals(cm.datatype)) { op.vendorExtensions.put("x-codegen-response-ishttpcontent", true); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ApexClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ApexClientCodegen.java index e88f1c7e665..cf32dd09a94 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ApexClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/ApexClientCodegen.java @@ -17,33 +17,37 @@ package org.openapitools.codegen.languages; -import com.sun.org.apache.xpath.internal.operations.Mod; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.info.Info; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.BooleanSchema; +import io.swagger.v3.oas.models.media.ByteArraySchema; +import io.swagger.v3.oas.models.media.EmailSchema; +import io.swagger.v3.oas.models.media.FileSchema; +import io.swagger.v3.oas.models.media.PasswordSchema; +import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.responses.ApiResponse; + import org.apache.commons.lang3.StringUtils; import org.openapitools.codegen.CliOption; -import org.openapitools.codegen.CodegenConfig; -import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenModel; import org.openapitools.codegen.CodegenOperation; import org.openapitools.codegen.CodegenParameter; import org.openapitools.codegen.CodegenProperty; import org.openapitools.codegen.CodegenType; -import org.openapitools.codegen.DefaultCodegen; import org.openapitools.codegen.SupportingFile; import org.openapitools.codegen.utils.ModelUtils; - -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.media.*; -import io.swagger.v3.oas.models.info.*; -import io.swagger.v3.oas.models.parameters.*; -import io.swagger.v3.parser.util.SchemaTypeUtil; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; public class ApexClientCodegen extends AbstractJavaCodegen { @@ -434,7 +438,7 @@ public class ApexClientCodegen extends AbstractJavaCodegen { if (op.getHasExamples()) { // prepare examples for Apex test classes ApiResponse responseProperty = findMethodResponse(operation.getResponses()); - String deserializedExample = toExampleValue(getSchemaFromResponse(responseProperty)); + String deserializedExample = toExampleValue(ModelUtils.getSchemaFromResponse(responseProperty)); for (Map example : op.examples) { example.put("example", escapeText(example.get("example"))); example.put("deserializedExample", deserializedExample); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppPistacheServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppPistacheServerCodegen.java index 65ed6ca2aa8..005904d817e 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppPistacheServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppPistacheServerCodegen.java @@ -17,6 +17,22 @@ package org.openapitools.codegen.languages; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.responses.ApiResponse; + +import org.apache.commons.lang3.StringUtils; +import org.openapitools.codegen.CodegenModel; +import org.openapitools.codegen.CodegenOperation; +import org.openapitools.codegen.CodegenParameter; +import org.openapitools.codegen.CodegenProperty; +import org.openapitools.codegen.CodegenType; +import org.openapitools.codegen.DefaultCodegen; +import org.openapitools.codegen.SupportingFile; +import org.openapitools.codegen.utils.ModelUtils; + import java.io.File; import java.util.Arrays; import java.util.HashMap; @@ -25,17 +41,6 @@ import java.util.List; import java.util.Map; import java.util.Set; -import io.swagger.v3.parser.util.SchemaTypeUtil; -import org.apache.commons.lang3.StringUtils; -import org.openapitools.codegen.*; -import org.openapitools.codegen.utils.ModelUtils; -import io.swagger.v3.oas.models.security.SecurityScheme; -import io.swagger.v3.oas.models.*; -import io.swagger.v3.oas.models.media.*; -import io.swagger.v3.oas.models.responses.ApiResponse; -import io.swagger.v3.oas.models.parameters.*; -import io.swagger.v3.core.util.Yaml; - public class CppPistacheServerCodegen extends AbstractCppCodegen { protected String implFolder = "impl"; @@ -161,7 +166,7 @@ public class CppPistacheServerCodegen extends AbstractCppCodegen { ApiResponse apiResponse = findMethodResponse(operation.getResponses()); if (apiResponse != null) { - Schema response = getSchemaFromResponse(apiResponse); + Schema response = ModelUtils.getSchemaFromResponse(apiResponse); if (response != null) { CodegenProperty cm = fromProperty("response", response); op.vendorExtensions.put("x-codegen-response", cm); diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppRestClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppRestClientCodegen.java index b50000ff4d0..998d15183f8 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppRestClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CppRestClientCodegen.java @@ -19,18 +19,16 @@ package org.openapitools.codegen.languages; import static com.google.common.base.Strings.isNullOrEmpty; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.Multimap; +import io.swagger.v3.oas.models.OpenAPI; +import io.swagger.v3.oas.models.Operation; +import io.swagger.v3.oas.models.media.ArraySchema; +import io.swagger.v3.oas.models.media.Schema; +import io.swagger.v3.oas.models.responses.ApiResponse; + import org.apache.commons.lang3.StringUtils; -import org.openapitools.codegen.CliOption; import org.openapitools.codegen.CodegenConstants; import org.openapitools.codegen.CodegenModel; import org.openapitools.codegen.CodegenOperation; @@ -39,11 +37,13 @@ import org.openapitools.codegen.CodegenProperty; import org.openapitools.codegen.CodegenType; import org.openapitools.codegen.SupportingFile; import org.openapitools.codegen.utils.ModelUtils; -import io.swagger.v3.oas.models.OpenAPI; -import io.swagger.v3.oas.models.Operation; -import io.swagger.v3.oas.models.media.*; -import io.swagger.v3.oas.models.responses.ApiResponse; -import io.swagger.v3.parser.util.SchemaTypeUtil; + +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; public class CppRestClientCodegen extends AbstractCppCodegen { @@ -238,7 +238,7 @@ public class CppRestClientCodegen extends AbstractCppCodegen { ApiResponse methodResponse = findMethodResponse(operation.getResponses()); if (methodResponse != null) { - Schema response = getSchemaFromResponse(methodResponse); + Schema response = ModelUtils.getSchemaFromResponse(methodResponse); if (response != null) { CodegenProperty cm = fromProperty("response", response); op.vendorExtensions.put("x-codegen-response", cm); 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 99ed3225203..22a689fe8df 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 @@ -25,6 +25,7 @@ import io.swagger.v3.oas.models.media.BinarySchema; import io.swagger.v3.oas.models.media.BooleanSchema; import io.swagger.v3.oas.models.media.ByteArraySchema; import io.swagger.v3.oas.models.media.ComposedSchema; +import io.swagger.v3.oas.models.media.Content; import io.swagger.v3.oas.models.media.DateSchema; import io.swagger.v3.oas.models.media.DateTimeSchema; import io.swagger.v3.oas.models.media.EmailSchema; @@ -48,6 +49,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -365,11 +367,14 @@ public class ModelUtils { return null; } - if (openAPI != null && openAPI.getComponents() != null && openAPI.getComponents().getSchemas() != null) { - return openAPI.getComponents().getSchemas().get(name); - } + return getSchemas(openAPI).get(name); + } - return null; + public static Map getSchemas(OpenAPI openAPI) { + if (openAPI != null && openAPI.getComponents() != null && openAPI.getComponents().getSchemas() != null) { + return openAPI.getComponents().getSchemas(); + } + return Collections.emptyMap(); } /** @@ -421,4 +426,21 @@ public class ModelUtils { } return null; } + + + public static Schema getSchemaFromRequestBody(RequestBody requestBody) { + return getSchemaFromContent(requestBody.getContent()); + } + + public static Schema getSchemaFromResponse(ApiResponse response) { + return getSchemaFromContent(response.getContent()); + } + + private static Schema getSchemaFromContent(Content content) { + if (content == null || content.isEmpty()) { + return null; + } + MediaType mediaType = content.values().iterator().next(); + return mediaType.getSchema(); + } } 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 9a1c9874826..d0bc83bd0d3 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 @@ -27,6 +27,8 @@ import io.swagger.v3.oas.models.responses.ApiResponse; import io.swagger.v3.oas.models.responses.ApiResponses; import io.swagger.v3.parser.core.models.ParseOptions; + +import org.openapitools.codegen.utils.ModelUtils; import org.testng.Assert; import org.testng.annotations.Test; @@ -183,9 +185,21 @@ public class DefaultCodegenTest { final OpenAPI openAPI = new OpenAPIParser().readLocation("src/test/resources/2_0/petstore-with-fake-endpoints-models-for-testing.yaml", null, new ParseOptions()).getOpenAPI(); final DefaultCodegen codegen = new DefaultCodegen(); - Schema requestBodySchema = codegen.getSchemaFromBody(openAPI.getPaths().get("/fake").getGet().getRequestBody()); + Schema requestBodySchema = ModelUtils.getSchemaFromRequestBody(openAPI.getPaths().get("/fake").getGet().getRequestBody()); CodegenParameter codegenParameter = codegen.fromFormProperty("enum_form_string", (Schema) requestBodySchema.getProperties().get("enum_form_string"), new HashSet()); Assert.assertEquals(codegenParameter.defaultValue, "-efg"); } + + @Test + public void testEnsureNoDuplicateProduces() { + final OpenAPI openAPI = new OpenAPIParser().readLocation("src/test/resources/3_0/two-responses.yaml", null, new ParseOptions()).getOpenAPI(); + final DefaultCodegen codegen = new DefaultCodegen(); + + Operation operation = openAPI.getPaths().get("/test").getGet(); + CodegenOperation co = codegen.fromOperation("/test", "get", operation, ModelUtils.getSchemas(openAPI), openAPI); + + Assert.assertEquals(co.produces.size(), 1); + Assert.assertEquals(co.produces.get(0).get("mediaType"), "application/json"); + } } diff --git a/modules/openapi-generator/src/test/resources/3_0/two-responses.yaml b/modules/openapi-generator/src/test/resources/3_0/two-responses.yaml new file mode 100644 index 00000000000..e4b030ba4aa --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/two-responses.yaml @@ -0,0 +1,29 @@ +openapi: 3.0.0 +info: + title: Test + version: 1.0.0 +servers: + - url: 'http://test/' +paths: + /test: + get: + summary: Test + responses: + '200': + description: Success + content: + application/json: + schema: + type: object + properties: + test: + type: string + '422': + description: Validation failed + content: + application/json: + schema: + type: object + properties: + test: + type: string \ No newline at end of file