Reputation: 26537
Does regular Spring (Boot) have a way to do global exception handling, or at least catch any uncaught exceptions (such as RuntimeException
that may happen randomly)?
I've googled around, but everything I've found talked about the @ControllerAdvice
@ExceptionHandler
for controllers. Nothing about just a general global exception handler.
I basically just want to make sure that if some exception happens that I'm not already catching, that I log it so I know about it.
Upvotes: 17
Views: 6823
Reputation: 1074
Best to extend Spring's ResponseEntityExceptionHandler
class and customise it in a way you want, for example:
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.Nullable;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
import javax.validation.ValidationException;
@ControllerAdvice
@Slf4j
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {
@ExceptionHandler(ValidationException.class)
protected ResponseEntity<Object> handle(ValidationException ex) {
return new ResponseEntity<>(getError(HttpStatus.BAD_REQUEST, ex), new HttpHeaders(), HttpStatus.BAD_REQUEST);
}
@ExceptionHandler
protected ResponseEntity<Object> handle(Exception ex, WebRequest request) {
try {
return super.handleException(ex, request);
} catch (Exception e) {
return handleExceptionInternal(ex, null, new HttpHeaders(), HttpStatus.INTERNAL_SERVER_ERROR, request);
}
}
@Override
protected ResponseEntity<Object> handleExceptionInternal(Exception ex, @Nullable Object body, HttpHeaders headers, HttpStatus status, WebRequest request) {
if (HttpStatus.Series.SERVER_ERROR == status.series()) {
log.error("Unexpected error.", ex);
}
return new ResponseEntity<>(getError(status, ex), headers, status);
}
private ApiError getError(HttpStatus status, Exception ex) {
return ApiError.builder()
.status(status.value())
.message(ex.getMessage())
.build();
}
}
This way you can override Spring's default error response body, declare your custom exceptions (e.g. ValidationException
) as well as allow Spring to handle its default exceptions declared in ResponseEntityExceptionHandler
.
Note although try-catch around
super.handleException(ex, request)
is not required in Spring 4.x, it is necessary in Spring 5.x due to a change of the underlyingResponseEntityExceptionHandler
implementation.
Upvotes: -2
Reputation: 7950
Add your own via AOP, something like this will work:
@Aspect
@Component
public class ExceptionHandler {
@AfterThrowing(pointcut = "within(*.*)", throwing = "t")
public void log(Throwable t) {
t.printStackTrace();
}
}
Look at the cheat sheet to help with the pointcut.
Upvotes: 2
Reputation: 1090
I think spring does not provide an out of the box solution for this.
A possibility to achieve this is using AOP with annotations (you may find an example here: Where can I catch non rest controller exceptions in spring?). With this approach, you can define a global pointcut for all the methods annotated with a pre-defined annotation. The good part of this approach is to have all the error handling logic in one place.
Upvotes: 4