-
Notifications
You must be signed in to change notification settings - Fork 438
Description
Description
The swagger code generator generates ambiguous code which compiles but does not run for endpoints with multiple content types. Take this example where the request body content type can be 'application/json' or 'multipart/form-data':
...
put:
summary: "Update a rule set with the supplied rule definitions."
operationId: "updateRuleSetWithRules"
parameters:
- name: "id"
in: "path"
required: true
style: "simple"
explode: false
schema:
type: "integer"
format: "int32"
requestBody:
description: "rules set with rules to be stored"
content:
application/json:
schema:
$ref: "#/components/schemas/RuleSetWithRulesVM"
multipart/form-data:
schema:
type: "object"
properties:
ruleSetCsvFile:
type: "string"
description: "The CSV file containing the rules."
format: "binary"
required: true
responses:
200:
...
The API file that gets generated contains the following to methods which the Java compiler can successfully compile:
...
@RequestMapping(value = "/ruleSets/{id}/rules",
produces = { "application/json" },
consumes = { "application/json", "multipart/form-data" },
method = RequestMethod.PUT)
default ResponseEntity<RuleSetWithRulesVM> updateRuleSetWithRules(@ApiParam(value = "rules set with rules to be stored" ,required=true ) @Valid @RequestBody RuleSetWithRulesVM body,@ApiParam(value = "",required=true) @PathVariable("id") Integer id) {
return getDelegate().updateRuleSetWithRules(body, id);
}
...
and
@RequestMapping(value = "/ruleSets/{id}/rules",
produces = { "application/json" },
consumes = { "application/json", "multipart/form-data" },
method = RequestMethod.PUT)
default ResponseEntity<RuleSetWithRulesVM> updateRuleSetWithRules(@ApiParam(value = "file detail") @Valid @RequestPart("file") MultipartFile ruleSetCsvFile,@ApiParam(value = "",required=true) @PathVariable("id") Integer id) {
return getDelegate().updateRuleSetWithRules(ruleSetCsvFile, id);
}
The problem arises when you start the resulting application because Spring is unable to distinguish between the two overloaded methods as they are missing the params option from the @RequestMapping annotation.
Swagger-codegen version
3.011-SNAPSHOT
Swagger declaration file content or url
/ruleSets/{id}/rules:
put:
tags:
- "rules"
summary: "Update a rule set with the supplied rule definitions."
operationId: "updateRuleSetWithRules"
parameters:
- name: "id"
in: "path"
required: true
style: "simple"
explode: false
schema:
type: "integer"
format: "int32"
requestBody:
description: "rules set with rules to be stored"
content:
application/json:
schema:
$ref: "#/components/schemas/RuleSetWithRulesVM"
multipart/form-data:
schema:
type: "object"
properties:
ruleSetCsvFile:
type: "string"
description: "The CSV file containing the rules."
format: "binary"
required: true
responses:
200:
description: "success"
content:
application/json:
schema:
$ref: "#/components/schemas/RuleSetWithRulesVM"Command line used for generation
The code is generated using Maven with the following configuration:
<configuration>
<ignoreFileOverride>${project.basedir}/src/main/resources/.swagger-codegen-ignore</ignoreFileOverride>
<inputSpec>${project.basedir}/src/main/resources/public/swagger-ml-classification-1.0.0.yaml</inputSpec>
<language>spring</language>
<configOptions>
<sourceFolder>src/main/java</sourceFolder>
<apiPackage>${default-server-package}.api</apiPackage>
<configPackage>${default-server-package}.configuration</configPackage>
<invokerPackage>${default-server-package}</invokerPackage>
<modelPackage>${default-server-package}.model</modelPackage>
<delegatePattern>true</delegatePattern>
<java8>true</java8>
<dateLibrary>java8</dateLibrary>
</configOptions>
</configuration>
Steps to reproduce
- Create an endpoint with two content types in the request body as shown above
- Generate the code for Spring Boot
- Run the resulting application to see the Spring startup errors
Related issues/PRs
None found
Suggest a fix/enhancement
To fix the problem, the code generator should generate code that includes the params option in the @RequestMapping annotation as shown in this example:
...
@RequestMapping(value = "/ruleSets/{id}/rules",
produces = { "application/json" },
consumes = { "application/json", "multipart/form-data" },
method = RequestMethod.PUT, params = {"body", "id"})
default ResponseEntity<RuleSetWithRulesVM> updateRuleSetWithRules(@ApiParam(value = "rules set with rules to be stored" ,required=true ) @Valid @RequestBody RuleSetWithRulesVM body,@ApiParam(value = "",required=true) @PathVariable("id") Integer id) {
return getDelegate().updateRuleSetWithRules(body, id);
}
...
@RequestMapping(value = "/ruleSets/{id}/rules",
produces = { "application/json" },
consumes = { "application/json", "multipart/form-data" },
method = RequestMethod.PUT, params = {"ruleSetCsvFile", "id"})
default ResponseEntity<RuleSetWithRulesVM> updateRuleSetWithRules(@ApiParam(value = "file detail") @Valid @RequestPart("file") MultipartFile ruleSetCsvFile,@ApiParam(value = "",required=true) @PathVariable("id") Integer id) {
return getDelegate().updateRuleSetWithRules(ruleSetCsvFile, id);
}
...
Please note the following changes in the suggested solution:
method = RequestMethod.PUT, params = {"body", "id"})
method = RequestMethod.PUT, params = {"ruleSetCsvFile", "id"})
Instead of the original:
method = RequestMethod.PUT)
method = RequestMethod.PUT)
The following patch could a be way of possibly fixing the issue but it will need work further work the params code is only generated under the right conditions:
diff --git a/src/main/resources/handlebars/JavaSpring/api.mustache b/src/main/resources/handlebars/JavaSpring/api.mustache
index 7551be6..bed2f10 100644
--- a/src/main/resources/handlebars/JavaSpring/api.mustache
+++ b/src/main/resources/handlebars/JavaSpring/api.mustache
@@ -101,7 +101,8 @@ public interface {{classname}} {
consumes = "{{{vendorExtensions.x-contentType}}}",{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}}
produces = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }, {{/hasProduces}}{{#hasConsumes}}
consumes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} },{{/hasConsumes}}{{/singleContentTypes}}
- method = RequestMethod.{{httpMethod}})
+ method = RequestMethod.{{httpMethod}},
+ params = { {{#parameters}}"{{paramName}}"{{#hasMore}}, {{/hasMore}}{{/parameters}} })
{{#jdk8}}default {{/jdk8}}{{#responseWrapper}}{{.}}<{{/responseWrapper}}ResponseEntity<{{>returnTypes}}>{{#responseWrapper}}>{{/responseWrapper}} {{#delegate-method}}_{{/delegate-method}}{{operationId}}({{#parameters}}{{>queryParams}}{{>pathParams}}{{>headerParams}}{{>bodyParams}}{{>formParams}}{{#hasMore}},{{/hasMore}}{{/parameters}}){{^jdk8}};{{/jdk8}}{{#jdk8}} {
{{#delegate-method}}
return {{operationId}}({{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}});
@@ -135,4 +136,4 @@ public interface {{classname}} {
{{/contents}}
{{/operation}}
}
-{{/operations}}
\ No newline at end of file
+{{/operations}}
diff --git a/src/main/resources/mustache/JavaSpring/api.mustache b/src/main/resources/mustache/JavaSpring/api.mustache
index c03be38..bed2f10 100644
--- a/src/main/resources/mustache/JavaSpring/api.mustache
+++ b/src/main/resources/mustache/JavaSpring/api.mustache
@@ -101,8 +101,8 @@ public interface {{classname}} {
consumes = "{{{vendorExtensions.x-contentType}}}",{{/hasConsumes}}{{/singleContentTypes}}{{^singleContentTypes}}{{#hasProduces}}
produces = { {{#produces}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/produces}} }, {{/hasProduces}}{{#hasConsumes}}
consumes = { {{#consumes}}"{{{mediaType}}}"{{#hasMore}}, {{/hasMore}}{{/consumes}} },{{/hasConsumes}}{{/singleContentTypes}}
- method = RequestMethod.{{httpMethod}}
- params = { {{#parameters}}{{paramName}}{{#hasMore}}, {{/hasMore}}{{/parameters}} })
: