Skip to content

Exceptions for missing request values should expose information when they are missing after conversion #26679

Closed
@drahkrub

Description

@drahkrub

In Spring 5.3 it is possible that a MissingServletRequestParameterException is thrown although a required parameter is provided (and therefore not missing). The same holds for a required path variable - even it is provided a MissingPathVariableException may be thrown.

Moreover the MissingServletRequestParameterException triggers a response status 400 in contrast to the MissingPathVariableException which ends up in a response status 500.

The former happens due to the changes made in #23939: If a provided parameter (request parameter or path variable) is converted to null it is handled as a missing value, see AbstractNamedValueMethodArgumentResolver.

I would like to propose:

  1. Adjust the response status.
  2. Throw a different exception (e.g. IllegalArgumentException) if a required parameter (request parameter or path variable) is provided but converted to null.

In a lengthy discussion with @rstoyanchev in #26088 (I thank his patience) I gave an example to explain that the current status is problematic:

  1. two users load the same book entity via its id, let's say 42
  2. one user deletes the book entity
  3. the other user continues using URLs with the id 42

I attached a small spring boot app with several test cases (github, spring_sandbox-master.zip).

With

@GetMapping(path = "/rp/book")
public Book getBookByRequestParam(@RequestParam("id") Book book) {
    ...

calling /rp/book?id=42 leads to a MissingServletRequestParameterException which is also thrown if /edit is called without a parameter or with an empty parameter - these cases can not be distinguished in an elegant way, see the tests

  • noRequestParamThrowsMissingServletRequestParameterException
  • emptyRequestParamThrowsMissingServletRequestParameterException
  • idOfDeletedBookThrowsMissingServletRequestParameterException

In contrast calling

@GetMapping({"/pv/book/{id}"})
public Book getBookByPathVariable(@PathVariable("id") Book book) {
    ...

with /pv/book/42 "only" leads to a misleading MissingPathVariableException, but the method can not be called with no or an empty parameter (if /pv/book is not mapped to a different method it is handled by the ResourceHttpRequestHandler, see the test missingValueNotHandledByController).

But a conflicting case can be constructed this way:

@GetMapping({"/cc/book", "/cc/book/{id}"})
public Book constructedCase(@PathVariable("id") Book book) {
    ...

Here calling /cc/book and /cc/book/42 both lead to a MissingPathVariableException - but as I said this is constructed resp. bad programming.

Metadata

Metadata

Assignees

Labels

in: webIssues in web modules (web, webmvc, webflux, websocket)type: enhancementA general enhancement

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions