user6058309
user6058309

Reputation: 63

Spring Boot @ControllerAdvice partially working, not working for custom exception

I'm having a peculiar situation with my @ControllerAdvice annotated ExceptionHandler in Spring Boot 1.5.3. It catches any exceptions default Exceptions, but if I throw a custom exception it does not fire.

The ExceptionHandler:

@ControllerAdvice
public class ResponseEntityExceptionHandler {

@ExceptionHandler({ HttpMessageNotReadableException.class })
protected ResponseEntity<ErrorModel> handleInvalidJson(RuntimeException e, WebRequest request) {
    return new ResponseEntity<ErrorModel>(new ErrorModel().message("Could not parse JSON."), HttpStatus.BAD_REQUEST);
}

@ExceptionHandler({ NumberFormatException.class })
protected ResponseEntity<ErrorModel> handleInvalidRequest(RuntimeException e, WebRequest request) {
    return new ResponseEntity<ErrorModel>(new ErrorModel().message("Invalid request parameter."), HttpStatus.BAD_REQUEST);
}

@ExceptionHandler({ CannotCreateTransactionException.class })
protected ResponseEntity<ErrorModel> handleTransactionCreationException(RuntimeException e, WebRequest request) {
    return new ResponseEntity<ErrorModel>(new ErrorModel().message("Error connecting to the database, please make sure it is still available."), HttpStatus.BAD_REQUEST);
}

@ExceptionHandler({ NotFoundException.class })
protected ResponseEntity<ErrorModel> handleApiException(RuntimeException e, WebRequest request) {
    return new ResponseEntity<ErrorModel>(new ErrorModel().message(e.getMessage()), HttpStatus.NOT_FOUND);
}
}

The top 3 Exceptions all get caught and handled as they are supposed to, but the bottom Exception gets handled by the default Spring-Boot ExceptionHandler. It is a custom Exception that I throw inside a Controller:

public ResponseEntity<?> deleteActor(@ApiParam(value = "Used to identify a single actor.", required = true) @PathVariable("actor_id") Integer actorId, @RequestHeader("Accept") String accept) throws Exception {
Actor actor = actorRepository.findOne(actorId);
if (actor == null) {
    throw new NotFoundException(404, "Not found");
}
actorRepository.delete(actorId);
return new ResponseEntity<Void>(HttpStatus.NO_CONTENT);
}

I've tried throwing one of the top Exceptions like this:

public ResponseEntity<?> readActor(@ApiParam(value = "Used to identify a single actor.", required = true) @PathVariable("actor_id") Integer actorId, @RequestHeader("Accept") String accept) throws Exception {
    Actor actor = actorRepository.findOne(actorId);
    if (actor == null) {
        throw new NumberFormatException("");
    }
    return new ResponseEntity<Actor>(actor, HttpStatus.OK);
}

and these get handled just fine...

The tomcat logs also show this:

2017-06-05 11:30:20.080  INFO 9076 --- [           main] .m.m.a.ExceptionHandlerExceptionResolver : Detected @ExceptionHandler methods in responseEntityExceptionHandler

The Exception:

public class NotFoundException extends ApiException {
private int code;
public NotFoundException (int code, String msg) {
    super(code, msg);
    this.code = code;
}
}

The exception inherits from this baseclass:

public class ApiException extends Exception{
private int code;
public ApiException (int code, String msg) {
    super(msg);
    this.code = code;
}
}

Any ideas about why the custom Exception avoids detection by the ExceptionHandler?

I would be happy to provide additional information should that be necessary.

Upvotes: 6

Views: 8195

Answers (2)

Nikita Sah
Nikita Sah

Reputation: 21

For me the CustomException was not getting caught by @ControllerAdvice method. I searched for hours and finally the issue got resolved on Updating the project. Right click on your project -> Maven -> Update project.

Upvotes: 0

rainerhahnekamp
rainerhahnekamp

Reputation: 1136

For this particular case the answer is to use Exception instead of RuntimeException, since NotFoundException does only inherit from Exception.

Further notable things:

  • To catch all exceptions one can use an @ExceptionHandler(Exception.class)

  • If using common names for exceptions, always check if you have imported the right one.

Upvotes: 3

Related Questions