Skip to content

Commit 65d3b60

Browse files
Use Flux only for multipart-form-data file parameters with multiple files
1 parent 473343f commit 65d3b60

4 files changed

Lines changed: 63 additions & 3 deletions

File tree

modules/openapi-generator/src/main/resources/JavaSpring/api.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,7 @@ public interface {{classname}} {
275275
}
276276

277277
// Override this method
278-
{{#jdk8-default-interface}}default {{/jdk8-default-interface}} {{>responseType}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}Flux<Part>{{/reactive}}{{^reactive}}{{#isArray}}List<MultipartFile>{{/isArray}}{{^isArray}}MultipartFile{{/isArray}}{{/reactive}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}{{#springFoxDocumentationProvider}}@ApiIgnore{{/springFoxDocumentationProvider}} final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}{{#springFoxDocumentationProvider}}@ApiIgnore{{/springFoxDocumentationProvider}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{#unhandledException}} throws Exception{{/unhandledException}} {
278+
{{#jdk8-default-interface}}default {{/jdk8-default-interface}} {{>responseType}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}{{#isArray}}Flux<{{/isArray}}Part{{#isArray}}>{{/isArray}}{{/reactive}}{{^reactive}}{{#isArray}}List<{{/isArray}}MultipartFile{{#isArray}}>{{/isArray}}{{/reactive}}{{/isFile}} {{paramName}}{{^-last}}, {{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}}, {{/hasParams}}{{#springFoxDocumentationProvider}}@ApiIgnore{{/springFoxDocumentationProvider}} final ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}{{#springFoxDocumentationProvider}}@ApiIgnore{{/springFoxDocumentationProvider}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{#unhandledException}} throws Exception{{/unhandledException}} {
279279
{{/delegate-method}}
280280
{{^isDelegate}}
281281
{{>methodBody}}{{! prevent indent}}

modules/openapi-generator/src/main/resources/JavaSpring/apiDelegate.mustache

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ public interface {{classname}}Delegate {
6868
{{#isDeprecated}}
6969
@Deprecated
7070
{{/isDeprecated}}
71-
{{#jdk8-default-interface}}default {{/jdk8-default-interface}}{{>responseType}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#isArray}}List<{{/isArray}}{{#reactive}}Flux<Part>{{/reactive}}{{^reactive}}{{#isFormParam}}MultipartFile{{/isFormParam}}{{^isFormParam}}{{>optionalDataType}}{{/isFormParam}}{{/reactive}}{{#isArray}}>{{/isArray}}{{/isFile}} {{paramName}}{{^-last}},
71+
{{#jdk8-default-interface}}default {{/jdk8-default-interface}}{{>responseType}} {{operationId}}({{#allParams}}{{^isFile}}{{^isBodyParam}}{{>optionalDataType}}{{/isBodyParam}}{{#isBodyParam}}{{^reactive}}{{>optionalDataType}}{{/reactive}}{{#reactive}}{{^isArray}}Mono<{{{dataType}}}>{{/isArray}}{{#isArray}}Flux<{{{baseType}}}>{{/isArray}}{{/reactive}}{{/isBodyParam}}{{/isFile}}{{#isFile}}{{#reactive}}{{#isArray}}Flux<{{/isArray}}Part{{#isArray}}>{{/isArray}}{{/reactive}}{{^reactive}}{{#isArray}}List<{{/isArray}}{{#isFormParam}}MultipartFile{{/isFormParam}}{{^isFormParam}}{{>optionalDataType}}{{/isFormParam}}{{#isArray}}>{{/isArray}}{{/reactive}}{{/isFile}} {{paramName}}{{^-last}},
7272
{{/-last}}{{/allParams}}{{#reactive}}{{#hasParams}},
7373
{{/hasParams}}ServerWebExchange exchange{{/reactive}}{{#vendorExtensions.x-spring-paginated}}{{#hasParams}}, {{/hasParams}}{{^hasParams}}{{#reactive}}, {{/reactive}}{{/hasParams}}final Pageable pageable{{/vendorExtensions.x-spring-paginated}}){{#unhandledException}} throws Exception{{/unhandledException}}{{^jdk8-default-interface}};{{/jdk8-default-interface}}{{#jdk8-default-interface}} {
7474
{{>methodBody}}{{! prevent indent}}
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
{{#isFormParam}}{{^isFile}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}} {{#isModel}}@RequestPart{{/isModel}}{{^isModel}}{{#isArray}}@RequestPart{{/isArray}}{{^isArray}}{{#reactive}}@RequestPart{{/reactive}}{{^reactive}}@RequestParam{{/reactive}}{{/isArray}}{{/isModel}}(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}){{>dateTimeParam}} {{^required}}{{#useOptional}}Optional<{{/useOptional}}{{/required}}{{{dataType}}}{{^required}}{{#useOptional}}>{{/useOptional}}{{/required}} {{paramName}}{{/isFile}}{{#isFile}}{{>paramDoc}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#isArray}}List<{{/isArray}}{{#reactive}}Flux<Part>{{/reactive}}{{^reactive}}MultipartFile{{/reactive}}{{#isArray}}>{{/isArray}} {{paramName}}{{/isFile}}{{/isFormParam}}
1+
{{#isFormParam}}{{^isFile}}{{>paramDoc}}{{#useBeanValidation}} @Valid{{/useBeanValidation}} {{#isModel}}@RequestPart{{/isModel}}{{^isModel}}{{#isArray}}@RequestPart{{/isArray}}{{^isArray}}{{#reactive}}@RequestPart{{/reactive}}{{^reactive}}@RequestParam{{/reactive}}{{/isArray}}{{/isModel}}(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}){{>dateTimeParam}} {{^required}}{{#useOptional}}Optional<{{/useOptional}}{{/required}}{{{dataType}}}{{^required}}{{#useOptional}}>{{/useOptional}}{{/required}} {{paramName}}{{/isFile}}{{#isFile}}{{>paramDoc}} @RequestPart(value = "{{baseName}}"{{#required}}, required = true{{/required}}{{^required}}, required = false{{/required}}) {{#reactive}}{{#isArray}}Flux<{{/isArray}}Part{{#isArray}}>{{/isArray}}{{/reactive}}{{^reactive}}{{#isArray}}List<{{/isArray}}MultipartFile{{#isArray}}>{{/isArray}}{{/reactive}} {{paramName}}{{/isFile}}{{/isFormParam}}

modules/openapi-generator/src/test/java/org/openapitools/codegen/java/spring/SpringCodegenTest.java

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -733,6 +733,66 @@ public void testMultipartBoot() throws IOException {
733733
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"statusArray\"", "required", "false"));
734734
}
735735

736+
@Test
737+
public void testReactiveMultipartBoot() throws IOException {
738+
final SpringCodegen codegen = new SpringCodegen();
739+
codegen.setLibrary("spring-boot");
740+
codegen.setDelegatePattern(true);
741+
codegen.additionalProperties().put(DOCUMENTATION_PROVIDER, "springfox");
742+
codegen.additionalProperties().put(SpringCodegen.REACTIVE, "true");
743+
744+
final Map<String, File> files = generateFiles(codegen, "src/test/resources/3_0/form-multipart-binary-array.yaml");
745+
746+
// Check that the delegate handles the array
747+
JavaFileAssert.assertThat(files.get("MultipartArrayApiDelegate.java"))
748+
.assertMethod("multipartArray", "Flux<Part>", "ServerWebExchange")
749+
.assertParameter("files").hasType("Flux<Part>");
750+
751+
// Check that the api handles the array
752+
JavaFileAssert.assertThat(files.get("MultipartArrayApi.java"))
753+
.assertMethod("multipartArray", "Flux<Part>", "ServerWebExchange")
754+
.assertParameter("files").hasType("Flux<Part>")
755+
.assertParameterAnnotations()
756+
.containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"Many files\""))
757+
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"files\"", "required", "false"));
758+
759+
// UPDATE: the following test has been ignored due to https://github.com/OpenAPITools/openapi-generator/pull/11081/
760+
// We will contact the contributor of the following test to see if the fix will break their use cases and
761+
// how we can fix it accordingly.
762+
//// Check that the delegate handles the single file
763+
// final File multipartSingleApiDelegate = files.get("MultipartSingleApiDelegate.java");
764+
// assertFileContains(multipartSingleApiDelegate.toPath(), "MultipartFile file");
765+
766+
// Check that the api handles the single file
767+
JavaFileAssert.assertThat(files.get("MultipartSingleApi.java"))
768+
.assertMethod("multipartSingle", "Part", "ServerWebExchange")
769+
.assertParameter("file").hasType("Part")
770+
.assertParameterAnnotations()
771+
.containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"One file\""))
772+
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"file\"", "required", "false"));
773+
774+
// Check that api validates mixed multipart request
775+
JavaFileAssert.assertThat(files.get("MultipartMixedApi.java"))
776+
.assertMethod("multipartMixed", "MultipartMixedStatus", "Part", "MultipartMixedRequestMarker", "List<MultipartMixedStatus>", "ServerWebExchange")
777+
.assertParameter("status").hasType("MultipartMixedStatus")
778+
.assertParameterAnnotations()
779+
.containsWithName("Valid")
780+
.containsWithNameAndAttributes("ApiParam", ImmutableMap.of("value", "\"\""))
781+
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"status\"", "required", "true"))
782+
.toParameter().toMethod()
783+
.assertParameter("file").hasType("Part")
784+
.assertParameterAnnotations()
785+
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"file\"", "required", "true"))
786+
.toParameter().toMethod()
787+
.assertParameter("marker").hasType("MultipartMixedRequestMarker")
788+
.assertParameterAnnotations()
789+
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"marker\"", "required", "false"))
790+
.toParameter().toMethod()
791+
.assertParameter("statusArray").hasType("List<MultipartMixedStatus>")
792+
.assertParameterAnnotations()
793+
.containsWithNameAndAttributes("RequestPart", ImmutableMap.of("value", "\"statusArray\"", "required", "false"));
794+
}
795+
736796
@Test
737797
public void testAdditionalProperties_issue1466() throws IOException {
738798
final SpringCodegen codegen = new SpringCodegen();

0 commit comments

Comments
 (0)