I am trying to perform some common logic that applies to all my @ExceptionHandler
s in code. I know I can write a HandlerInterceptor
to intercept happy paths. But I would like to hook into the exception handling lifecycle so that I can execute some common logic such as logging, before the error response is rendered.
Is there anyway to do this in Spring Boot / Spring MVC? I would like to avoid having to write a servlet filter for this purpose if possible.
You can define the @ExceptionHandler method to handle the exceptions as shown. This method should be used for writing the Controller Advice class file. Now, use the code given below to throw the exception from the API. The complete code to handle the exception is given below.
The differences between @RestControllerAdvice and @ControllerAdvice is : @RestControllerAdvice = @ControllerAdvice + @ResponseBody . - we can use in REST web services. @ControllerAdvice - We can use in both MVC and Rest web services, need to provide the ResponseBody if we use this in Rest web services.
We can use try catch block to protect the code. Catch block is used to catch all types of exception. The keyword “catch” is used to catch exceptions.
public abstract class ResponseEntityExceptionHandler extends Object. A convenient base class for @ControllerAdvice classes that wish to provide centralized exception handling across all @RequestMapping methods through @ExceptionHandler methods.
There is a way with @RestControllerAdvice
and @ExceptionHandler
, an example:
@RestControllerAdvice
public class GlobalControllerExceptionHandler {
@ExceptionHandler(value = {DeniedPermissionException.class})
@ResponseStatus(HttpStatus.FORBIDDEN)
public String deniedPermissionException(DeniedPermissionException ex) {
return "Denied permission";
}
@ExceptionHandler(value = {ConstraintViolationException.class})
@ResponseStatus(HttpStatus.BAD_REQUEST)
public String constraintViolationException(ConstraintViolationException ex) {
return "Bad request";
}
@ExceptionHandler(value = {Exception.class})
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
public String internalServerError(Exception ex) {
return "Internal error";
}
}
*DeniedPermissionException
is a custom exception.
I have a solution. It's about using HandlerInterceptor.afterCompletion
method. However, there is a line in the documentation of this method that states that:
Note: Will only be called if this interceptor's preHandle method has successfully completed and returned true!
So the trick is to also implement the preHandle
and make it return true
.
Now my interceptor looks like this:
@Component
public class MyInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
// perform common logic here
}
}
One thing to be aware of though is that if you have a chain of interceptors and an interceptor before this one throws an exception, this interceptor won't get a chance to execute. So if we reorder the interceptor chain so that MyInterceptor
is right at the top, it will intercept all requests.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With