Description
For a multipart/form-data request body, the generated Spring controller interface is not usable as-is:
- No
@RequestPart / @RequestParam binding annotation. The whole multipart body is collapsed into a single generated wrapper DTO passed as a bare @Valid parameter (the only effect of the form-data branch is that @RequestBody is omitted). Spring cannot bind multipart parts this way.
- No
consumes declaration. The @RequestMapping hard-codes produces = {"application/json"} and never advertises consumes = MediaType.MULTIPART_FORM_DATA_VALUE, even though the operation's consumes list is already computed.
- The wrapper DTO is immutable. It is generated as an immutable Lombok
@Value type (builder only, no no-arg constructor / setters), so even Spring's default @ModelAttribute binding cannot instantiate it at runtime.
Steps to reproduce
paths:
/test:
post:
operationId: testMultipart
requestBody:
required: true
content:
multipart/form-data:
schema:
type: object
properties:
someString:
type: string
someFile:
type: string
format: binary
Actual result
@RequestMapping(method = RequestMethod.POST, value = "/test", produces = {"application/json"})
default ResponseEntity<Void> testMultipart(@Valid InlineObjectTestMultipart inlineObjectTestMultipart) { ... }
No @RequestPart, no consumes, and InlineObjectTestMultipart is an immutable @Value class.
Expected result
Each multipart part exposed as its own @RequestPart, files as MultipartFile / List<MultipartFile>, plus a consumes declaration:
@RequestMapping(method = RequestMethod.POST, value = "/test",
produces = {"application/json"},
consumes = {MediaType.MULTIPART_FORM_DATA_VALUE})
default ResponseEntity<Void> testMultipart(
@RequestPart(value = "someString", required = false) String someString,
@RequestPart(value = "someFile", required = false) MultipartFile someFile) { ... }
Root cause
templates/openapi/template.ftlh only uses the isFormData flag to drop @RequestBody; it never emits @RequestPart/consumes. OpenApiUtil.processRequestBody registers the multipart schema as a wrapper model regardless.
Environment
- Affects the OpenAPI code generator (
multiapi-engine), Spring server interface template.
- Reproduced on
main.
Description
For a
multipart/form-datarequest body, the generated Spring controller interface is not usable as-is:@RequestPart/@RequestParambinding annotation. The whole multipart body is collapsed into a single generated wrapper DTO passed as a bare@Validparameter (the only effect of the form-data branch is that@RequestBodyis omitted). Spring cannot bind multipart parts this way.consumesdeclaration. The@RequestMappinghard-codesproduces = {"application/json"}and never advertisesconsumes = MediaType.MULTIPART_FORM_DATA_VALUE, even though the operation's consumes list is already computed.@Valuetype (builder only, no no-arg constructor / setters), so even Spring's default@ModelAttributebinding cannot instantiate it at runtime.Steps to reproduce
Actual result
No
@RequestPart, noconsumes, andInlineObjectTestMultipartis an immutable@Valueclass.Expected result
Each multipart part exposed as its own
@RequestPart, files asMultipartFile/List<MultipartFile>, plus aconsumesdeclaration:Root cause
templates/openapi/template.ftlhonly uses theisFormDataflag to drop@RequestBody; it never emits@RequestPart/consumes.OpenApiUtil.processRequestBodyregisters the multipart schema as a wrapper model regardless.Environment
multiapi-engine), Spring server interface template.main.