diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java index 5963b8791b03d29e9339cbe0aa36ac4d3dca07aa..6c90108d05f5d30dd75fed0e078570a58cef9d0d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/CodegenParameter.java @@ -28,7 +28,7 @@ public class CodegenParameter { isCookieParam, isBodyParam, hasMore, isContainer, secondaryParam, isCollectionFormatMulti, isPrimitiveType, isModel; public String baseName, paramName, dataType, datatypeWithEnum, dataFormat, - collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName; + collectionFormat, description, unescapedDescription, baseType, defaultValue, enumName, contentType; public String example; // example value (x-example) public String jsonSchema; 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 f911c5c48afd7f9053e32c8b6f875ceaa440bf10..ab6310ab34c94b8368788e2397aad7a24ef67a56 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 @@ -17,7 +17,6 @@ package org.openapitools.codegen; -import com.fasterxml.jackson.core.JsonProcessingException; import com.google.common.base.CaseFormat; import com.google.common.collect.ImmutableMap; import com.samskivert.mustache.Mustache; @@ -2679,16 +2678,16 @@ public class DefaultCodegen implements CodegenConfig { List<CodegenParameter> requiredParams = new ArrayList<CodegenParameter>(); List<CodegenParameter> optionalParams = new ArrayList<CodegenParameter>(); - CodegenParameter bodyParam = null; RequestBody requestBody = operation.getRequestBody(); if (requestBody != null) { - String contentType = getContentType(requestBody); - if (contentType != null && - (contentType.toLowerCase(Locale.ROOT).startsWith("application/x-www-form-urlencoded") || - contentType.toLowerCase(Locale.ROOT).startsWith("multipart"))) { + // TODO: all of the bodyParams should be parsed together, including form data + String firstContentType = getFirstContentType(requestBody); + if (firstContentType != null && + (firstContentType.toLowerCase(Locale.ROOT).startsWith("application/x-www-form-urlencoded") || + firstContentType.toLowerCase(Locale.ROOT).startsWith("multipart"))) { // process form parameters formParams = fromRequestBodyToFormParameters(requestBody, imports); - op.isMultipart = contentType.toLowerCase(Locale.ROOT).startsWith("multipart"); + op.isMultipart = firstContentType.toLowerCase(Locale.ROOT).startsWith("multipart"); for (CodegenParameter cp : formParams) { postProcessParameter(cp); } @@ -2706,19 +2705,29 @@ public class DefaultCodegen implements CodegenConfig { if (op.vendorExtensions != null && op.vendorExtensions.containsKey("x-codegen-request-body-name")) { bodyParameterName = (String) op.vendorExtensions.get("x-codegen-request-body-name"); } - bodyParam = fromRequestBody(requestBody, imports, bodyParameterName); - bodyParam.description = escapeText(requestBody.getDescription()); - postProcessParameter(bodyParam); + // retrieves all of the potential bodyParams from the Content field of the RequestBody section + List<CodegenParameter> requestBodyParams = fromRequestBody(requestBody, imports, bodyParameterName); + for (CodegenParameter bodyParam : requestBodyParams) { + bodyParam.description = escapeText(requestBody.getDescription()); + postProcessParameter(bodyParam); - bodyParams.add(bodyParam); + bodyParams.add(bodyParam); - if (prependFormOrBodyParameters) { - allParams.add(bodyParam); + // add example + if (schemas != null) { + op.requestBodyExamples = new ExampleGenerator(schemas, this.openAPI).generate(null, new ArrayList<String>(getConsumesInfo(this.openAPI, operation)), bodyParam.baseType); + } } - - // add example - if (schemas != null) { - op.requestBodyExamples = new ExampleGenerator(schemas, this.openAPI).generate(null, new ArrayList<String>(getConsumesInfo(this.openAPI, operation)), bodyParam.baseType); + // TODO: many generators expect allParams to only have one bodyParam in it + // generators should either expect multiple bodyParam options in the allParams, + // or the bodyParam should be excluded from allParams and treated specially. + if (prependFormOrBodyParameters) { + try { + CodegenParameter firstBodyParam = requestBodyParams.get(0); + allParams.add(firstBodyParam); + } catch (IndexOutOfBoundsException e) { + LOGGER.warn("No bodyParam available to prepend to allParams"); + } } } } @@ -2759,8 +2768,13 @@ public class DefaultCodegen implements CodegenConfig { allParams.add(cp.copy()); } - for (CodegenParameter cp : bodyParams) { - allParams.add(cp.copy()); + // TODO: many generators expect allParams to only have one bodyParam in it + // generators should either expect multiple bodyParam options in the allParams, + // or the bodyParam should be excluded from allParams and treated specially. + try { + allParams.add(bodyParams.get(0).copy()); + } catch (IndexOutOfBoundsException e) { + LOGGER.warn("No bodyParam available to append to allParams"); } } @@ -2781,7 +2795,11 @@ public class DefaultCodegen implements CodegenConfig { } } - op.bodyParam = bodyParam; + try { + op.bodyParam = bodyParams.get(0); + } catch (IndexOutOfBoundsException e) { + op.bodyParam = null; + } op.httpMethod = httpMethod.toUpperCase(Locale.ROOT); // move "required" parameters in front of "optional" parameters @@ -4419,7 +4437,7 @@ public class DefaultCodegen implements CodegenConfig { additionalProperties.put(propertyKey, value); } - protected String getContentType(RequestBody requestBody) { + protected String getFirstContentType(RequestBody requestBody) { if (requestBody == null || requestBody.getContent() == null || requestBody.getContent().isEmpty()) { LOGGER.debug("Cannot determine the content type. Returning null."); return null; @@ -4773,246 +4791,254 @@ public class DefaultCodegen implements CodegenConfig { return codegenParameter; } - public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, String bodyParameterName) { + public List<CodegenParameter> fromRequestBody(RequestBody body, Set<String> imports, String bodyParameterName) { if (body == null) { LOGGER.error("body in fromRequestBody cannot be null!"); throw new RuntimeException("body in fromRequestBody cannot be null!"); } - CodegenParameter codegenParameter = CodegenModelFactory.newInstance(CodegenModelType.PARAMETER); - codegenParameter.baseName = "UNKNOWN_BASE_NAME"; - codegenParameter.paramName = "UNKNOWN_PARAM_NAME"; - codegenParameter.description = escapeText(body.getDescription()); - codegenParameter.required = body.getRequired() != null ? body.getRequired() : Boolean.FALSE; - codegenParameter.isBodyParam = Boolean.TRUE; - - String name = null; - LOGGER.debug("Request body = " + body); - Schema schema = ModelUtils.getSchemaFromRequestBody(body); - if (schema == null) { - throw new RuntimeException("Request body cannot be null. Possible cause: missing schema in body parameter (OAS v2): " + body); - } + List<CodegenParameter> codegenParameters = new ArrayList<>(); + for (Map.Entry<String, MediaType> entry : body.getContent().entrySet()) { + String contentType = entry.getKey(); + MediaType mediaType = entry.getValue(); - if (StringUtils.isNotBlank(schema.get$ref())) { - name = ModelUtils.getSimpleRef(schema.get$ref()); - } - schema = ModelUtils.getReferencedSchema(this.openAPI, schema); + CodegenParameter codegenParameter = CodegenModelFactory.newInstance(CodegenModelType.PARAMETER); + codegenParameter.baseName = "UNKNOWN_BASE_NAME"; + codegenParameter.paramName = "UNKNOWN_PARAM_NAME"; + codegenParameter.description = escapeText(body.getDescription()); + codegenParameter.required = body.getRequired() != null ? body.getRequired() : Boolean.FALSE; + codegenParameter.isBodyParam = Boolean.TRUE; + codegenParameter.contentType = contentType; - if (ModelUtils.isMapSchema(schema)) { - Schema inner = ModelUtils.getAdditionalProperties(schema); - if (inner == null) { - LOGGER.error("No inner type supplied for map parameter `{}`. Default to type:string", schema.getName()); - inner = new StringSchema().description("//TODO automatically added by openapi-generator"); - schema.setAdditionalProperties(inner); + String name = null; + LOGGER.debug("Request body = " + body); + Schema schema = mediaType.getSchema(); + if (schema == null) { + throw new RuntimeException("Request body cannot be null. Possible cause: missing schema in body parameter (OAS v2): " + body); } - CodegenProperty codegenProperty = fromProperty("property", schema); - - imports.add(codegenProperty.baseType); - CodegenProperty innerCp = codegenProperty; - while (innerCp != null) { - if (innerCp.complexType != null) { - imports.add(innerCp.complexType); - } - innerCp = innerCp.items; + if (StringUtils.isNotBlank(schema.get$ref())) { + name = ModelUtils.getSimpleRef(schema.get$ref()); } + schema = ModelUtils.getReferencedSchema(this.openAPI, schema); - if (StringUtils.isEmpty(bodyParameterName)) { - codegenParameter.baseName = "request_body"; - } else { - codegenParameter.baseName = bodyParameterName; - } - codegenParameter.paramName = toParamName(codegenParameter.baseName); - codegenParameter.items = codegenProperty.items; - codegenParameter.mostInnerItems = codegenProperty.mostInnerItems; - codegenParameter.dataType = getTypeDeclaration(schema); - codegenParameter.baseType = getSchemaType(inner); - codegenParameter.isContainer = Boolean.TRUE; - codegenParameter.isMapContainer = Boolean.TRUE; + if (ModelUtils.isMapSchema(schema)) { + Schema inner = ModelUtils.getAdditionalProperties(schema); + if (inner == null) { + LOGGER.error("No inner type supplied for map parameter `{}`. Default to type:string", schema.getName()); + inner = new StringSchema().description("//TODO automatically added by openapi-generator"); + schema.setAdditionalProperties(inner); + } + CodegenProperty codegenProperty = fromProperty("property", schema); - setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + imports.add(codegenProperty.baseType); - // set nullable - setParameterNullable(codegenParameter, codegenProperty); - } else if (ModelUtils.isArraySchema(schema)) { - final ArraySchema arraySchema = (ArraySchema) schema; - Schema inner = getSchemaItems(arraySchema); - if (arraySchema.getItems() == null) { - arraySchema.setItems(inner); - } - CodegenProperty codegenProperty = fromProperty("property", arraySchema); - imports.add(codegenProperty.baseType); - CodegenProperty innerCp = codegenProperty; - CodegenProperty mostInnerItem = innerCp; - // loop through multidimensional array to add proper import - // also find the most inner item - while (innerCp != null) { - if (innerCp.complexType != null) { - imports.add(innerCp.complexType); + CodegenProperty innerCp = codegenProperty; + while (innerCp != null) { + if (innerCp.complexType != null) { + imports.add(innerCp.complexType); + } + innerCp = innerCp.items; } - mostInnerItem = innerCp; - innerCp = innerCp.items; - } - if (StringUtils.isEmpty(bodyParameterName)) { - if (StringUtils.isEmpty(mostInnerItem.complexType)) { + if (StringUtils.isEmpty(bodyParameterName)) { codegenParameter.baseName = "request_body"; } else { - codegenParameter.baseName = mostInnerItem.complexType; + codegenParameter.baseName = bodyParameterName; } - } else { - codegenParameter.baseName = bodyParameterName; - } - codegenParameter.paramName = toArrayModelParamName(codegenParameter.baseName); - codegenParameter.items = codegenProperty.items; - codegenParameter.mostInnerItems = codegenProperty.mostInnerItems; - codegenParameter.dataType = getTypeDeclaration(arraySchema); - codegenParameter.baseType = getSchemaType(inner); - codegenParameter.isContainer = Boolean.TRUE; - codegenParameter.isListContainer = Boolean.TRUE; + codegenParameter.paramName = toParamName(codegenParameter.baseName); + codegenParameter.items = codegenProperty.items; + codegenParameter.mostInnerItems = codegenProperty.mostInnerItems; + codegenParameter.dataType = getTypeDeclaration(schema); + codegenParameter.baseType = getSchemaType(inner); + codegenParameter.isContainer = Boolean.TRUE; + codegenParameter.isMapContainer = Boolean.TRUE; - setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); - // set nullable - setParameterNullable(codegenParameter, codegenProperty); + setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); - while (codegenProperty != null) { + // set nullable + setParameterNullable(codegenParameter, codegenProperty); + } else if (ModelUtils.isArraySchema(schema)) { + final ArraySchema arraySchema = (ArraySchema) schema; + Schema inner = getSchemaItems(arraySchema); + if (arraySchema.getItems() == null) { + arraySchema.setItems(inner); + } + CodegenProperty codegenProperty = fromProperty("property", arraySchema); imports.add(codegenProperty.baseType); - codegenProperty = codegenProperty.items; - } + CodegenProperty innerCp = codegenProperty; + CodegenProperty mostInnerItem = innerCp; + // loop through multidimensional array to add proper import + // also find the most inner item + while (innerCp != null) { + if (innerCp.complexType != null) { + imports.add(innerCp.complexType); + } + mostInnerItem = innerCp; + innerCp = innerCp.items; + } - } else if (ModelUtils.isFreeFormObject(schema)) { - // HTTP request body is free form object - CodegenProperty codegenProperty = fromProperty("FREE_FORM_REQUEST_BODY", schema); - if (codegenProperty != null) { if (StringUtils.isEmpty(bodyParameterName)) { - codegenParameter.baseName = "body"; // default to body + if (StringUtils.isEmpty(mostInnerItem.complexType)) { + codegenParameter.baseName = "request_body"; + } else { + codegenParameter.baseName = mostInnerItem.complexType; + } } else { codegenParameter.baseName = bodyParameterName; } - codegenParameter.isPrimitiveType = true; - codegenParameter.baseType = codegenProperty.baseType; - codegenParameter.dataType = codegenProperty.dataType; - codegenParameter.description = codegenProperty.description; - codegenParameter.paramName = toParamName(codegenParameter.baseName); - } - setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); - // set nullable - setParameterNullable(codegenParameter, codegenProperty); + codegenParameter.paramName = toArrayModelParamName(codegenParameter.baseName); + codegenParameter.items = codegenProperty.items; + codegenParameter.mostInnerItems = codegenProperty.mostInnerItems; + codegenParameter.dataType = getTypeDeclaration(arraySchema); + codegenParameter.baseType = getSchemaType(inner); + codegenParameter.isContainer = Boolean.TRUE; + codegenParameter.isListContainer = Boolean.TRUE; - } else if (ModelUtils.isObjectSchema(schema) || ModelUtils.isComposedSchema(schema)) { - CodegenModel codegenModel = null; - if (StringUtils.isNotBlank(name)) { - schema.setName(name); - codegenModel = fromModel(name, schema); - } - if (codegenModel != null) { - codegenParameter.isModel = true; - } + setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + // set nullable + setParameterNullable(codegenParameter, codegenProperty); - if (codegenModel != null && !codegenModel.emptyVars) { - if (StringUtils.isEmpty(bodyParameterName)) { - codegenParameter.baseName = codegenModel.classname; - } else { - codegenParameter.baseName = bodyParameterName; + while (codegenProperty != null) { + imports.add(codegenProperty.baseType); + codegenProperty = codegenProperty.items; } - codegenParameter.paramName = toParamName(codegenParameter.baseName); - codegenParameter.baseType = codegenModel.classname; - codegenParameter.dataType = getTypeDeclaration(codegenModel.classname); - codegenParameter.description = codegenModel.description; - imports.add(codegenParameter.baseType); - } else { - CodegenProperty codegenProperty = fromProperty("property", schema); - if (codegenProperty != null && codegenProperty.getComplexType() != null && codegenProperty.getComplexType().contains(" | ")) { - List<String> parts = Arrays.asList(codegenProperty.getComplexType().split(" \\| ")); - imports.addAll(parts); - String codegenModelName = codegenProperty.getComplexType(); - codegenParameter.baseName = codegenModelName; + } else if (ModelUtils.isFreeFormObject(schema)) { + // HTTP request body is free form object + CodegenProperty codegenProperty = fromProperty("FREE_FORM_REQUEST_BODY", schema); + if (codegenProperty != null) { + if (StringUtils.isEmpty(bodyParameterName)) { + codegenParameter.baseName = "body"; // default to body + } else { + codegenParameter.baseName = bodyParameterName; + } + codegenParameter.isPrimitiveType = true; + codegenParameter.baseType = codegenProperty.baseType; + codegenParameter.dataType = codegenProperty.dataType; + codegenParameter.description = codegenProperty.description; codegenParameter.paramName = toParamName(codegenParameter.baseName); - codegenParameter.baseType = codegenParameter.baseName; - codegenParameter.dataType = getTypeDeclaration(codegenModelName); - codegenParameter.description = codegenProperty.getDescription(); - } else { - if (ModelUtils.getAdditionalProperties(schema) != null) {// http body is map - LOGGER.error("Map should be supported. Please report to openapi-generator github repo about the issue."); - } else if (codegenProperty != null) { - String codegenModelName, codegenModelDescription; - - if (codegenModel != null) { - codegenModelName = codegenModel.classname; - codegenModelDescription = codegenModel.description; - } else { - LOGGER.warn("The following schema has undefined (null) baseType. " + - "It could be due to form parameter defined in OpenAPI v2 spec with incorrect consumes. " + - "A correct 'consumes' for form parameters should be " + - "'application/x-www-form-urlencoded' or 'multipart/?'"); - LOGGER.warn("schema: " + schema); - LOGGER.warn("codegenModel is null. Default to UNKNOWN_BASE_TYPE"); - codegenModelName = "UNKNOWN_BASE_TYPE"; - codegenModelDescription = "UNKNOWN_DESCRIPTION"; - } + } + setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + // set nullable + setParameterNullable(codegenParameter, codegenProperty); - if (StringUtils.isEmpty(bodyParameterName)) { - codegenParameter.baseName = codegenModelName; - } else { - codegenParameter.baseName = bodyParameterName; - } + } else if (ModelUtils.isObjectSchema(schema) || ModelUtils.isComposedSchema(schema)) { + CodegenModel codegenModel = null; + if (StringUtils.isNotBlank(name)) { + schema.setName(name); + codegenModel = fromModel(name, schema); + } + if (codegenModel != null) { + codegenParameter.isModel = true; + } + if (codegenModel != null && !codegenModel.emptyVars) { + if (StringUtils.isEmpty(bodyParameterName)) { + codegenParameter.baseName = codegenModel.classname; + } else { + codegenParameter.baseName = bodyParameterName; + } + codegenParameter.paramName = toParamName(codegenParameter.baseName); + codegenParameter.baseType = codegenModel.classname; + codegenParameter.dataType = getTypeDeclaration(codegenModel.classname); + codegenParameter.description = codegenModel.description; + imports.add(codegenParameter.baseType); + } else { + CodegenProperty codegenProperty = fromProperty("property", schema); + + if (codegenProperty != null && codegenProperty.getComplexType() != null && codegenProperty.getComplexType().contains(" | ")) { + List<String> parts = Arrays.asList(codegenProperty.getComplexType().split(" \\| ")); + imports.addAll(parts); + String codegenModelName = codegenProperty.getComplexType(); + codegenParameter.baseName = codegenModelName; codegenParameter.paramName = toParamName(codegenParameter.baseName); - codegenParameter.baseType = codegenModelName; + codegenParameter.baseType = codegenParameter.baseName; codegenParameter.dataType = getTypeDeclaration(codegenModelName); - codegenParameter.description = codegenModelDescription; - imports.add(codegenParameter.baseType); + codegenParameter.description = codegenProperty.getDescription(); + } else { + if (ModelUtils.getAdditionalProperties(schema) != null) {// http body is map + LOGGER.error("Map should be supported. Please report to openapi-generator github repo about the issue."); + } else if (codegenProperty != null) { + String codegenModelName, codegenModelDescription; + + if (codegenModel != null) { + codegenModelName = codegenModel.classname; + codegenModelDescription = codegenModel.description; + } else { + LOGGER.warn("The following schema has undefined (null) baseType. " + + "It could be due to form parameter defined in OpenAPI v2 spec with incorrect consumes. " + + "A correct 'consumes' for form parameters should be " + + "'application/x-www-form-urlencoded' or 'multipart/?'"); + LOGGER.warn("schema: " + schema); + LOGGER.warn("codegenModel is null. Default to UNKNOWN_BASE_TYPE"); + codegenModelName = "UNKNOWN_BASE_TYPE"; + codegenModelDescription = "UNKNOWN_DESCRIPTION"; + } - if (codegenProperty.complexType != null) { - imports.add(codegenProperty.complexType); + if (StringUtils.isEmpty(bodyParameterName)) { + codegenParameter.baseName = codegenModelName; + } else { + codegenParameter.baseName = bodyParameterName; + } + + codegenParameter.paramName = toParamName(codegenParameter.baseName); + codegenParameter.baseType = codegenModelName; + codegenParameter.dataType = getTypeDeclaration(codegenModelName); + codegenParameter.description = codegenModelDescription; + imports.add(codegenParameter.baseType); + + if (codegenProperty.complexType != null) { + imports.add(codegenProperty.complexType); + } } } + + setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + // set nullable + setParameterNullable(codegenParameter, codegenProperty); } - setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); - // set nullable - setParameterNullable(codegenParameter, codegenProperty); - } + } else { + // HTTP request body is primitive type (e.g. integer, string, etc) + CodegenProperty codegenProperty = fromProperty("PRIMITIVE_REQUEST_BODY", schema); + if (codegenProperty != null) { + if (StringUtils.isEmpty(bodyParameterName)) { + codegenParameter.baseName = "body"; // default to body + } else { + codegenParameter.baseName = bodyParameterName; + } + codegenParameter.isPrimitiveType = true; + codegenParameter.baseType = codegenProperty.baseType; + codegenParameter.dataType = codegenProperty.dataType; + codegenParameter.description = codegenProperty.description; + codegenParameter.paramName = toParamName(codegenParameter.baseName); + codegenParameter.minimum = codegenProperty.minimum; + codegenParameter.maximum = codegenProperty.maximum; + codegenParameter.exclusiveMinimum = codegenProperty.exclusiveMinimum; + codegenParameter.exclusiveMaximum = codegenProperty.exclusiveMaximum; + codegenParameter.minLength = codegenProperty.minLength; + codegenParameter.maxLength = codegenProperty.maxLength; + codegenParameter.pattern = codegenProperty.pattern; - } else { - // HTTP request body is primitive type (e.g. integer, string, etc) - CodegenProperty codegenProperty = fromProperty("PRIMITIVE_REQUEST_BODY", schema); - if (codegenProperty != null) { - if (StringUtils.isEmpty(bodyParameterName)) { - codegenParameter.baseName = "body"; // default to body - } else { - codegenParameter.baseName = bodyParameterName; - } - codegenParameter.isPrimitiveType = true; - codegenParameter.baseType = codegenProperty.baseType; - codegenParameter.dataType = codegenProperty.dataType; - codegenParameter.description = codegenProperty.description; - codegenParameter.paramName = toParamName(codegenParameter.baseName); - codegenParameter.minimum = codegenProperty.minimum; - codegenParameter.maximum = codegenProperty.maximum; - codegenParameter.exclusiveMinimum = codegenProperty.exclusiveMinimum; - codegenParameter.exclusiveMaximum = codegenProperty.exclusiveMaximum; - codegenParameter.minLength = codegenProperty.minLength; - codegenParameter.maxLength = codegenProperty.maxLength; - codegenParameter.pattern = codegenProperty.pattern; + if (codegenProperty.complexType != null) { + imports.add(codegenProperty.complexType); + } - if (codegenProperty.complexType != null) { - imports.add(codegenProperty.complexType); } - + setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); + // set nullable + setParameterNullable(codegenParameter, codegenProperty); } - setParameterBooleanFlagWithCodegenProperty(codegenParameter, codegenProperty); - // set nullable - setParameterNullable(codegenParameter, codegenProperty); - } - // set the parameter's example value - // should be overridden by lang codegen - setParameterExampleValue(codegenParameter, body); + // set the parameter's example value + // should be overridden by lang codegen + setParameterExampleValue(codegenParameter, body); + codegenParameters.add(codegenParameter); + } - return codegenParameter; + return codegenParameters; } protected void addOption(String key, String description, String defaultValue) { diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientExperimentalCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientExperimentalCodegen.java index 71dd5d61133e3a50ac66b5d9f88488b4ab24fbf6..821494abae86abdb935b7cbbffff92df16d7db4d 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientExperimentalCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/PythonClientExperimentalCodegen.java @@ -314,8 +314,9 @@ public class PythonClientExperimentalCodegen extends PythonClientCodegen { } @Override - public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, String bodyParameterName) { - CodegenParameter result = super.fromRequestBody(body, imports, bodyParameterName); + public List<CodegenParameter> fromRequestBody(RequestBody body, Set<String> imports, String bodyParameterName) { + List<CodegenParameter> results = super.fromRequestBody(body, imports, bodyParameterName); + CodegenParameter result = results.get(0); // if we generated a model with a non-object type because it has validations or enums, // make sure that the datatype of that body parameter refers to our model class Content content = body.getContent(); @@ -325,7 +326,7 @@ public class PythonClientExperimentalCodegen extends PythonClientCodegen { Schema schema = mediaType.getSchema(); String ref = schema.get$ref(); if (ref == null) { - return result; + return results; } String modelName = ModelUtils.getSimpleRef(ref); // the result lacks validation info so we need to make a CodegenProperty from the schema to check @@ -346,7 +347,7 @@ public class PythonClientExperimentalCodegen extends PythonClientCodegen { result.example = modelName + "(" + result.example + ")"; } } - return result; + return results; } /** diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java index 9e227b3eee093c45aa5979f8c49491b976ce52e5..ff1c35bf7da42c075163f8d7d96d7edff559d050 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/RustServerCodegen.java @@ -786,9 +786,10 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { // Thus, we grab the inner schema beforehand, and then tinker afterwards to // restore things to sensible values. @Override - public CodegenParameter fromRequestBody(RequestBody body, Set<String> imports, String bodyParameterName) { + public List<CodegenParameter> fromRequestBody(RequestBody body, Set<String> imports, String bodyParameterName) { Schema original_schema = ModelUtils.getSchemaFromRequestBody(body); - CodegenParameter codegenParameter = super.fromRequestBody(body, imports, bodyParameterName); + List<CodegenParameter> codegenParameters = super.fromRequestBody(body, imports, bodyParameterName); + CodegenParameter codegenParameter = codegenParameters.get(0); if (StringUtils.isNotBlank(original_schema.get$ref())) { // Undo the mess `super.fromRequestBody` made - re-wrap the inner @@ -809,7 +810,7 @@ public class RustServerCodegen extends DefaultCodegen implements CodegenConfig { } } - return codegenParameter; + return codegenParameters; } @Override 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 26ae76afc1bc067edfcd84766356d43b1f36f5d7..5efe35ad98168bf029bb05cda15db485bb799274 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 @@ -922,7 +922,7 @@ public class DefaultCodegenTest { RequestBody body = openAPI.getPaths().get("/examples").getPost().getRequestBody(); - CodegenParameter codegenParameter = codegen.fromRequestBody(body, imports, ""); + CodegenParameter codegenParameter = codegen.fromRequestBody(body, imports, "").get(0); Assert.assertTrue(codegenParameter.isContainer); Assert.assertTrue(codegenParameter.items.isModel); @@ -940,13 +940,33 @@ public class DefaultCodegenTest { RequestBody body = openAPI.getPaths().get("/examples").getPost().getRequestBody(); - CodegenParameter codegenParameter = codegen.fromRequestBody(body, imports, ""); + CodegenParameter codegenParameter = codegen.fromRequestBody(body, imports, "").get(0); Assert.assertTrue(codegenParameter.isContainer); Assert.assertTrue(codegenParameter.items.isModel); Assert.assertFalse(codegenParameter.items.isContainer); } + @Test + public void multipleRequestBodyParams() { + final OpenAPI openAPI = TestUtils.parseSpec("src/test/resources/3_0/request_body_two_content_types.yaml"); + new InlineModelResolver().flatten(openAPI); + final DefaultCodegen codegen = new DefaultCodegen(); + codegen.setOpenAPI(openAPI); + + Set<String> imports = new HashSet<>(); + + RequestBody body = openAPI.getPaths().get("/transactions").getPost().getRequestBody(); + + List<CodegenParameter> codegenParameters = codegen.fromRequestBody(body, imports, ""); + + Assert.assertEquals(2, codegenParameters.size()); + + List<String> paramContentTypes = codegenParameters.stream().map(param -> param.contentType).collect(Collectors.toList()); + Assert.assertTrue(paramContentTypes.contains("application/vnd.transaction.transaction.v1+json")); + Assert.assertTrue(paramContentTypes.contains("application/vnd.transaction.transaction.v2+json")); + } + @Test @SuppressWarnings("unchecked") public void commonLambdasRegistrationTest() { diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/bash/BashTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/bash/BashTest.java index ff05821a59efcadfc4b38b25411dbb1bdc0c7a1b..14a8770eaa662b3187e456184403d8e3bd2fd9bd 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/bash/BashTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/bash/BashTest.java @@ -76,7 +76,7 @@ public class BashTest { addPetOperation, null); - Assert.assertEquals(op.bodyParams.size(), 1); + Assert.assertEquals(op.bodyParams.size(), 2); CodegenParameter p = op.bodyParams.get(0); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java index 2f8a8d31c9bab8a740efe51110232db07915ab65..0489a5bfc4ed6502ed7a3c8f363c383563d21b7c 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/java/JavaClientCodegenTest.java @@ -77,7 +77,7 @@ public class JavaClientCodegenTest { RequestBody body1 = new RequestBody(); body1.setDescription("A list of ids"); body1.setContent(new Content().addMediaType("application/json", new MediaType().schema(new ArraySchema().items(new StringSchema())))); - CodegenParameter codegenParameter1 = codegen.fromRequestBody(body1, new HashSet<String>(), null); + CodegenParameter codegenParameter1 = codegen.fromRequestBody(body1, new HashSet<String>(), null).get(0); Assert.assertEquals(codegenParameter1.description, "A list of ids"); Assert.assertEquals(codegenParameter1.dataType, "List<String>"); Assert.assertEquals(codegenParameter1.baseType, "String"); @@ -85,7 +85,7 @@ public class JavaClientCodegenTest { RequestBody body2 = new RequestBody(); body2.setDescription("A list of list of values"); body2.setContent(new Content().addMediaType("application/json", new MediaType().schema(new ArraySchema().items(new ArraySchema().items(new IntegerSchema()))))); - CodegenParameter codegenParameter2 = codegen.fromRequestBody(body2, new HashSet<String>(), null); + CodegenParameter codegenParameter2 = codegen.fromRequestBody(body2, new HashSet<String>(), null).get(0); Assert.assertEquals(codegenParameter2.description, "A list of list of values"); Assert.assertEquals(codegenParameter2.dataType, "List<List<Integer>>"); Assert.assertEquals(codegenParameter2.baseType, "List"); @@ -97,7 +97,7 @@ public class JavaClientCodegenTest { point.addProperties("message", new StringSchema()); point.addProperties("x", new IntegerSchema().format(SchemaTypeUtil.INTEGER32_FORMAT)); point.addProperties("y", new IntegerSchema().format(SchemaTypeUtil.INTEGER32_FORMAT)); - CodegenParameter codegenParameter3 = codegen.fromRequestBody(body3, new HashSet<String>(), null); + CodegenParameter codegenParameter3 = codegen.fromRequestBody(body3, new HashSet<String>(), null).get(0); Assert.assertEquals(codegenParameter3.description, "A list of points"); Assert.assertEquals(codegenParameter3.dataType, "List<Point>"); Assert.assertEquals(codegenParameter3.baseType, "Point"); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/ruby/RubyClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/ruby/RubyClientCodegenTest.java index b7bd1c69a51a52a421eb3e0daf9db3600d78178f..5274fdae619b4dfa74f9c1c63eed66abcd70b3f0 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/ruby/RubyClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/ruby/RubyClientCodegenTest.java @@ -158,7 +158,7 @@ public class RubyClientCodegenTest { final String path = "/pet"; final Operation p = openAPI.getPaths().get(path).getPost(); final CodegenOperation op = codegen.fromOperation(path, "post", p, null); - Assert.assertEquals(op.bodyParams.size(), 1); + Assert.assertEquals(op.bodyParams.size(), 2); CodegenParameter bp = op.bodyParams.get(0); Assert.assertEquals(bp.example, "OnlinePetstore::Pet.new"); } diff --git a/modules/openapi-generator/src/test/resources/3_0/request_body_two_content_types.yaml b/modules/openapi-generator/src/test/resources/3_0/request_body_two_content_types.yaml new file mode 100644 index 0000000000000000000000000000000000000000..b901a31efe2868a36800eb7bd38a8d0291772abd --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/request_body_two_content_types.yaml @@ -0,0 +1,35 @@ +openapi: 3.0.0 +info: + title: Test + version: 1.0.0 +servers: + - url: 'http://test/' +paths: + /transactions: + post: + summary: Endpoint for posting a new transaction + requestBody: + description: Post + content: + application/vnd.transaction.transaction.v1+json: + schema: + $ref: '#/components/schemas/TransactionV1' + application/vnd.transaction.transaction.v2+json: + schema: + $ref: '#/components/schemas/TransactionV2' + responses: + '204': + description: Transaction created +components: + schemas: + TransactionV1: + type: object + properties: + test1: + type: string + + TransactionV2: + type: object + properties: + test2: + type: string