Spring Boot - how to differentiate between validation for @PathVariable and query params (@RequestParam)

Viewed 378

How to use custom validation/binding for query params (@RequestParam)? For wrong type in @PathVariable I want to receive 404 error, for wrong parameter types for @RequestParam I want to receive 400 or nothing.

I have @ControllerAdvice

@ExceptionHandler(value = {MethodArgumentTypeMismatchException.class})
    protected ResponseEntity handleException(NativeWebRequest request, MethodArgumentTypeMismatchException ex) {
        String error = ex.getName() + " in request URL should be of type " + ex.getRequiredType().getName();
        return create(HttpStatus.NOT_FOUND, error, ex);
    }

This exception handler catches all cases with wrong type on @PathVariable. BUT - I'd like to not throw any error in case of wrong type for query params - I want to return empty list in case of wrong query parameters OR maybe return error 400 instead.

 @GetMapping("/v3/tw")
 public Page<TwDto> getTwByFilter(
            @RequestParam(name = "filter", defaultValue = "{}", required = false) @Valid TwSearchDto filter,
            @RequestParam(name = "sort", defaultValue = "{}", required = false) @Valid TwSortDto sort,
            @RequestParam(name = "page", defaultValue = "1", required = false) @Min(1) @ApiParam(value = "Minimum value: 1") int page,
            @RequestParam(name = "size", defaultValue = "10", required = false) @Min(1) @Max(100) @ApiParam(value = "Minimum value: 1\n\nMaximum value: 100") int size,
            Authentication authentication) {
        return twSearchService.getTwPage(filter, sort, page, size, authentication);
    }

In case of invalid parameters like page 0 where minimum is 1 @Min(1) I want to return error code 400 (current behaviour that is working right now)

Currently in case of:

 /api/rest/v2/tw?page=1string

error code 404 is returned (in debug mode I go to ExceptionHandler mentioned above) but I don't want to throw any error 404 - instead I'd like to throw error code 400.

How to differentiate between these 2 cases in my ControllerAdvice? Or maybe better I should not throw any error and just return empty list?

Or maybe another question - is it possible to check in ExceptionHandler if the exceptions comes from @RequestParam?

1 Answers

The answer is very simple - we have to fetch proper data from our exception like this:

HttpStatus status = ex.getParameter().getParameterAnnotation(PathVariable.class) != null ? HttpStatus.NOT_FOUND : HttpStatus.BAD_REQUEST;

So this exception handler in my @ControllerAdvice is responsible for handling and differentiating errors caused by wrong type in @PathVariable and @RequestParam

@ExceptionHandler(value = {MethodArgumentTypeMismatchException.class})
    protected ResponseEntity<Object> handleException(NativeWebRequest request, MethodArgumentTypeMismatchException ex) {
        String error;
        if (ex.getRequiredType() != null) {
            error = ex.getName() + " in request URL should be of type " + ex.getRequiredType().getName();
        } else {
            error = ex.getMessage();
        }
        HttpStatus status = ex.getParameter().getParameterAnnotation(PathVariable.class) != null ? HttpStatus.NOT_FOUND : HttpStatus.BAD_REQUEST;
        return create(status, error, ex);
    }

And this exception handler handles all wrong types in objects (endpoint payload):

 @Override
    @NonNull
    protected ResponseEntity<Object> handleHttpMessageNotReadable(@NonNull HttpMessageNotReadableException ex, @NonNull HttpHeaders headers, @NonNull HttpStatus status, @NonNull WebRequest request) {
        String message;
        if (ex.getCause() instanceof InvalidFormatException) {
            InvalidFormatException exception = (InvalidFormatException) ex.getCause();
            message = String.format("Cannot deserialize value of type %s from %s", exception.getTargetType(), exception.getValue());
        } else {
            message = ex.getMessage();
        }
        return create(HttpStatus.BAD_REQUEST, message, ex);
    }

I hope this answer will be helpful for you

Related