exception handling for filter in spring exception handling for filter in spring spring spring

exception handling for filter in spring


Filters happens before controllers are even resolved so exceptions thrown from filters can't be caught by a Controller Advice.

Filters are a part of the servlet and not really the MVC stack.


As the exception is not raised from a controller but a filter, @ControllerAdvice won't catch it.

So, the best solution i found after looking everywhere was to create a filter for this internal errors:

public class ExceptionHandlerFilter extends OncePerRequestFilter {    @Override    public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {        try {            filterChain.doFilter(request, response);        } catch (JwtException e) {            setErrorResponse(HttpStatus.BAD_REQUEST, response, e);            e.printStackTrace();        } catch (RuntimeException e) {            e.printStackTrace();            setErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR, response, e);        }    }    public void setErrorResponse(HttpStatus status, HttpServletResponse response, Throwable ex){        response.setStatus(status.value());        response.setContentType("application/json");        // A class used for errors        ApiError apiError = new ApiError(status, ex);        try {            String json = apiError.convertToJson();            System.out.println(json);            response.getWriter().write(json);        } catch (IOException e) {            e.printStackTrace();        }    }}

Add it to your config, i'm using a WebSecurityConfigurerAdapter implementation:

// Custom JWT based security filterhttpSecurity        .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);// Custom Exception Filter for filterhttpSecurity        .addFilterBefore(exceptionHandlerFilterBean(), JwtAuthenticationTokenFilter.class);

The error class:

public class ApiError {    private HttpStatus status;    @JsonSerialize(using = LocalDateTimeSerializer.class)    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd-MM-yyyy hh:mm:ss")    private LocalDateTime timestamp;    private String message;    private String debugMessage;    private ApiError() {        timestamp = LocalDateTime.now();    }    public ApiError(HttpStatus status) {        this();        this.status = status;    }    public ApiError(HttpStatus status, Throwable ex) {        this();        this.status = status;        this.message = "Unexpected error";        this.debugMessage = ex.getLocalizedMessage();    }    public ApiError(HttpStatus status, String message, Throwable ex) {        this();        this.status = status;        this.message = message;        this.debugMessage = ex.getLocalizedMessage();    }    public String convertToJson() throws JsonProcessingException {        if (this == null) {            return null;        }        ObjectMapper mapper = new ObjectMapper();        mapper.registerModule(new JavaTimeModule());        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);        return mapper.writeValueAsString(this);    }  //Setters and getters}


Presumably, you want to set the HTTP Status code as a result of the exception being thrown in the Filter? If so, simply set the status as follows:

HttpServletResponse response = (HttpServletResponse) res;response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);