6
votes

In @ControllerAdvice class I have an @ExceptionHandler, this handler works well with controller errors but if I have a filter they can't handle the exception. How can I handle these exceptions?

The filter is:-

public class AuthFilter extends UsernamePasswordAuthenticationFilter {

    private LoginDTO loginDTO;

    public AuthFilter() {
        setRequiresAuthenticationRequestMatcher(
                new AntPathRequestMatcher("/login", "POST"));
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request,
            HttpServletResponse response) throws AuthenticationException {

        try {
            loginDTO = new ObjectMapper().readValue(request.getReader(), LoginDTO.class);
        } catch (Exception e) {
            throw new APIException(ExceptionMessages.INVALID_LOGIN_JSON,
                    HttpStatus.BAD_REQUEST);
        }

        return super.attemptAuthentication(request, response);
    }

    ...
}

The exception handler is (in @ControllerAdvice)

    @ExceptionHandler(APIException.class)
    public ResponseEntity<ErrorDTO> handleAPIException(APIException e) {
        return new ResponseEntity<ErrorDTO>(new ErrorDTO(e.getMessage()),
                e.getHttpStatus());
    }

UPDATE

My requirement is having a global exception handler for spring security filters. Is there any way to do it?

1
Those errors are handled by Spring Security not by an @ExceptionHandler as those are only for controllers and execute within the DispatcherServlet filters execute before filters so no way an @ExceptionHandler (without moving it to another filter, basically duplicating the dispatcherservlet to a filter) can handle this (nor should it imho). Also you are aware that your custom filter is flawed? - M. Deinum
So is there a way to handle spring security exceptions globally? No, not really, what is the flaw? - Kaushik
Spring Security already handles those exceptions, what is wrong with that? You have a single filter and for each request you store the result in a class level attribute, the loginDTO now what do you think what happens when 10 requests come in.... - M. Deinum
I want a JSON error message. For every request won't it create a new instance? What is the solution, then? - Kaushik
That is the problem as this instance is stored inside a single instance of the filter, that is shared, so request 1 is overriding request 2. If you want a JSON response create a custom ExceptionHandlingFilter. But what is your use case, why are you doing this? - M. Deinum

1 Answers

5
votes

I'm afraid you cannot. Here is (broadly) how à request is processed in a Spring MVC web application :

servlet container
    filters before FilterChain.doFilter
        DispatcherServlet  => here is all Spring MVC machinery
    filters after FilterChain.doFilter
servlet container

All Spring MVC machinery is managed inside the DispatcherServlet, including all exception handling.

IMHO, you can try two things :

  • replace the filter with an interceptor (*)
  • use another filter coming before the one where exception is thrown and catch it there (the non Spring MVC way, but filters are outside of Spring MVC)

(*) You will still not be able to use an ExceptionHandler since exception will be thrown outside of a controller, but you could use a HandlerExceptionResolver.