The current structure of UnsatisfiedServletRequestParameterException does not provide custom exception handlers with enough flexibility in producing response bodies.

For example, assuming that we have the following two controllers:

@RestController
public class Controller1 {

    @PostMapping(
        params = "action=foo"
    )
    public ResponseEntity<...> handle(...) {

    }

}

@RestController
public class Controller2 {

    @PostMapping(
        params = "action=bar"
    )
    public ResponseEntity<...> handle(...) {

    }

}

In response to an invalid action parameter such as xxx, a developer may want to handle the resulting UnsatisfiedServletRequestParameterException and respond with a message like this:

{
    "message" : "Invalid parameter",
    "parameterName" : "action",
    "parameterValue" : "xxx"
}

However at the moment there's not a straightforward, clean, and elegant option to produce such a custom message.

Another current option, which is also not clean, is to extend RequestMappingInfoHandlerMapping' and override its handleNoMatch method, but this method combines handling of different types of mismatches and overriding it would require copy/pasting the entire method body and changing the if (helper.hasParamsMismatch()) { clause:

    /**
     * Iterate all RequestMappingInfo's once again, look if any match by URL at
     * least and raise exceptions according to what doesn't match.
     * @throws HttpRequestMethodNotSupportedException if there are matches by URL
     * but not by HTTP method
     * @throws HttpMediaTypeNotAcceptableException if there are matches by URL
     * but not by consumable/producible media types
     */
    @Override
    protected HandlerMethod handleNoMatch(
            Set<RequestMappingInfo> infos, String lookupPath, HttpServletRequest request) throws ServletException {

        PartialMatchHelper helper = new PartialMatchHelper(infos, request);
        if (helper.isEmpty()) {
            return null;
        }

        if (helper.hasMethodsMismatch()) {
            Set<String> methods = helper.getAllowedMethods();
            if (HttpMethod.OPTIONS.matches(request.getMethod())) {
                HttpOptionsHandler handler = new HttpOptionsHandler(methods);
                return new HandlerMethod(handler, HTTP_OPTIONS_HANDLE_METHOD);
            }
            throw new HttpRequestMethodNotSupportedException(request.getMethod(), methods);
        }

        if (helper.hasConsumesMismatch()) {
            Set<MediaType> mediaTypes = helper.getConsumableMediaTypes();
            MediaType contentType = null;
            if (StringUtils.hasLength(request.getContentType())) {
                try {
                    contentType = MediaType.parseMediaType(request.getContentType());
                }
                catch (InvalidMediaTypeException ex) {
                    throw new HttpMediaTypeNotSupportedException(ex.getMessage());
                }
            }
            throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<>(mediaTypes));
        }

        if (helper.hasProducesMismatch()) {
            Set<MediaType> mediaTypes = helper.getProducibleMediaTypes();
            throw new HttpMediaTypeNotAcceptableException(new ArrayList<>(mediaTypes));
        }

        if (helper.hasParamsMismatch()) {
            // CHANGE HERE
            List<String[]> conditions = helper.getParamConditions();
            throw new UnsatisfiedServletRequestParameterException(conditions, request.getParameterMap());
        }

        return null;
    }

It would be nice if RequestMappingInfoHandlerMapping was implementing the strategy pattern so we could inject custom strategies for handling "method mismatch", "consumes mismatch", "produces mismatch", and "params mismatch" and throwing custom exceptions from our custom strategies.

Comment From: rstoyanchev

at the moment there's not a straightforward, clean, and elegant option to produce such a custom message.

Could you elaborate, what is missing and what would you like to see in UnsatisfiedServletRequestParameterException?

Comment From: behrangsa

at the moment there's not a straightforward, clean, and elegant option to produce such a custom message.

Could you elaborate, what is missing and what would you like to see in UnsatisfiedServletRequestParameterException?

Unfortunately I can't remember! I suppose we can close this issue. :sweat_smile: