Search code examples
spring-bootvalidationexceptioncontrolleruuid

ControllerAdvice isn't picking IllegalArgumentException thrown by an incorrect UUID value passed as @RequestParam


I have the following controller:

@Slf4j
@RestController
@RequestMapping("/v1")
@Validated
public class HighlightController {
    // ...
    @GetMapping("/highlights")
    public ResponseEntity<List<Highlight>> getHighlights(
            @RequestParam(required = false) UUID impersonateUserId
    ) {
      // ...

Then I have the following controller exception handler:

@Slf4j
@ControllerAdvice
public class GlobalExceptionHandler {

    //...

    @ExceptionHandler(value = IllegalArgumentException.class)
    public ResponseEntity<Object> handleIllegalArgumentException(IllegalArgumentException ex) {
        log.info("Handled: IllegalArgumentException", ex);
        return buildResponseEntity(new ApiErrorResponse(
                HttpStatus.BAD_REQUEST,
                "Incorrect Request",
                ex
        ));
    }

    @ExceptionHandler(value = RuntimeException.class)
    public ResponseEntity<Object> handleRuntimeException(RuntimeException ex) {
        log.error("Handled: Runtime exception", ex);
        return buildResponseEntity(new ApiErrorResponse(
                HttpStatus.INTERNAL_SERVER_ERROR,
                "Internal error",
                ex
        ));
    }
 
    //...

    private ResponseEntity<Object> buildResponseEntity(ApiErrorResponse errorResponse) {
        return new ResponseEntity<>(errorResponse, errorResponse.getStatus());
    }

When I send a request to v1/highlights endpoint with an incorrect UUID valie, I would expect that the IllegalArgumentException thrown by StringToUUIDConverter when parsing UUID from String value would be caught by handleIllegalArgumentException, but instead, it is handled by handleRuntimeException. Why is that?


Solution

  • If you call your controller, for example like:

    http://localhost:8080/v1/highligths?impersonateUserId=x
    

    what would be the result? For me it is not IllegalArgumentException.

    Have a look what I got:

    There was an unexpected error (type=Bad Request, status=400).
    Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; nested exception is java.lang.IllegalArgumentException: Invalid UUID string: x org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; nested exception is java.lang.IllegalArgumentException: Invalid UUID string: x

    So could it be that you should handle MethodArgumentTypeMismatchException?

    I admit it is a bit confusing that the first lines suggest the cause to be IllegalArguemntException.

    If I call:

    localhost:8080/v1/highligths?impersonateUserId=123e4567-e89b-12d3-a456-556642440000
    

    everything seems to be ok.

    If I then call:

    http://localhost:8080/v1/highligths?impersonateUserId=123e4567-e89b-12d3-a456-556642440000x
    

    I get:

    There was an unexpected error (type=Bad Request, status=400).
    Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; nested exception is java.lang.IllegalArgumentException: UUID string too large org.springframework.web.method.annotation.MethodArgumentTypeMismatchException: Failed to convert value of type 'java.lang.String' to required type 'java.util.UUID'; nested exception is java.lang.IllegalArgumentException: UUID string too large

    But again, the exception thrown is actually:

    MethodArgumentTypeMismatchException