What is the difference between @RequestParam and @RequestPart for multipart requests?
answer
- @RequestParam = simple conversion, ignores Content-Type
- @RequestPart = HttpMessageConverters, honors Content-Type
- JSON metadata part → @RequestPart
- @RequestPart supports @Valid per part
- single file: either works
basics
~20 s@RequestParam does simple type conversion and works for text fields and MultipartFile. @RequestPart considers each part's Content-Type and uses HttpMessageConverters — so it can deserialize a JSON part into an object, like @RequestBody per part.
solid answer
~40 sBoth bind parts of a multipart/form-data request, but they resolve values differently. @RequestParam treats the part as a simple value: it works for MultipartFile/Part and for plain form fields, applying registered Converters/PropertyEditors (String → target). It ignores the part's Content-Type. @RequestPart honors each part's Content-Type header and runs it through the same HttpMessageConverters used by @RequestBody — so a part with Content-Type: application/json is deserialized (via Jackson) into a POJO, and Bean Validation (@Valid) can apply. Use @RequestParam for files and scalar fields; use @RequestPart when a part carries structured content (JSON/XML) that needs message-converter deserialization, or when you want per-part validation. Both handle MultipartFile equally, so for a single file either works.
code
java · 11 lines// JSON metadata + binary file in one multipart request
@PostMapping(path = "/documents", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<Doc> create(
@RequestPart("metadata") @Valid DocMeta meta, // part Content-Type: application/json -> Jackson
@RequestPart("file") MultipartFile file, // binary part
@RequestParam("tag") String tag) { // simple form field -> String conversion
// meta is a fully deserialized, validated POJO
return ResponseEntity.ok(service.store(meta, tag, file));
}
record DocMeta(@NotBlank String title, @Positive int version) {}go deeper
Know both bind multipart parts and that @RequestParam is used for simple files/fields.
Explain converter-based deserialization and Content-Type sensitivity of @RequestPart vs simple conversion of @RequestParam.
Discuss per-part @Valid, converter selection failures, and mixed JSON+file API design.
Weigh multipart-with-JSON API ergonomics vs alternatives (base64 in JSON, separate upload endpoints) and client interoperability.
## Both bind multipart parts — the resolution differs A `multipart/form-data` request is a sequence of *parts*. Two annotations bind them, but through different Spring machinery. ### `@RequestParam` - Backed by `RequestParamMethodArgumentResolver`. - Treats the part/field as a **simple value**. For `String`/`int`/etc. it applies Spring's **type conversion** (registered `Converter`s / `PropertyEditor`s: `String → target`). For `MultipartFile` / `jakarta.servlet.http.Part` it hands you the raw part. - **Ignores the part's `Content-Type`.** A JSON part bound as `@RequestParam String` gives you the raw JSON *string*, not a parsed object. - Also binds ordinary query/form params — it's not multipart-specific. ### `@RequestPart` - Backed by `RequestPartMethodArgumentResolver`. - **Honors the part's `Content-Type`** and passes it through the configured **`HttpMessageConverter`s** — exactly like `@RequestBody` does for the whole body, but per part. - So a part sent with `Content-Type: application/json` is deserialized (e.g., by `MappingJackson2HttpMessageConverter`) into a target POJO. A part can also be a `MultipartFile`/`Part`. - Supports `@Valid` for **per-part Bean Validation**, raising `MethodArgumentNotValidException` on failure. ## Concrete example An API takes a JSON `metadata` part plus a binary `file` part: ```java @PostMapping(path="/documents", consumes=MediaType.MULTIPART_FORM_DATA_VALUE) public Doc create(@RequestPart("metadata") @Valid DocMeta meta, @RequestPart("file") MultipartFile file) { ... } ``` Here `metadata` must be deserialized from JSON → `@RequestPart` is required (with `@RequestParam` you'd get a raw String). The client must set `Content-Type: application/json` on the `metadata` part; otherwise Jackson may not be selected and you get `HttpMediaTypeNotSupportedException` / a 415-style failure. ## For a plain file For a single file with no structured metadata, `@RequestParam("file") MultipartFile` and `@RequestPart("file") MultipartFile` behave the same — both give you the `MultipartFile`. ## Gotchas - **Missing part**: both throw `MissingServletRequestPartException` (or `MissingServletRequestParameterException`) when `required=true` (default) and the part is absent. - **Part Content-Type matters only for `@RequestPart`.** Clients (e.g., some HTTP libraries) omit per-part `Content-Type`; then converter selection can fail. `@RequestParam` sidesteps this for simple values. - **Validation**: only `@RequestPart` (like `@RequestBody`) participates in `@Valid` message-converter validation; `@RequestParam` validation relies on `@Validated` at the controller + constraint annotations on the param. ## When to use which - Files, checkboxes, text fields, numbers → `@RequestParam`. - A part that is a JSON/XML document to deserialize, or that needs `@Valid` → `@RequestPart`.
- The client sends a JSON part but you bound it with @RequestParam String — what do you get?The raw JSON as a String (no deserialization), because @RequestParam ignores the part Content-Type and applies only simple String conversion. You'd have to parse it manually. Use @RequestPart to get a deserialized POJO.
- Why might @RequestPart deserialization fail with 415 even though the JSON is valid?The client didn't set Content-Type: application/json on that part. Without it, Spring can't select the Jackson HttpMessageConverter, so converter resolution fails (HttpMediaTypeNotSupportedException).
saying these in an interview costs you the question
- Saying @RequestPart can't bind MultipartFile (it can).
- Claiming @RequestParam deserializes a JSON part into an object.
- Thinking the two are interchangeable in all cases (they differ for structured parts and validation).
- Believing @RequestParam runs HttpMessageConverters.