I have two filters in my spring boot application.
One of the filters, RequestResponseLoggingFilter, resposible for request and response logging. This filter must be executed last. I can’t change its order
@Component
@Order(10000)
@Slf4j
@RequiredArgsConstructor
public class RequestResponseLoggingFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
if (requestResponseLoggingEnabled) {
if (isAsyncDispatch(request)) {
filterChain.doFilter(request, response);
} else {
doFilterWrapped(wrapRequest(request), wrapResponse(response), filterChain);
}
} else {
filterChain.doFilter(request, response);
}
}
protected void doFilterWrapped(
ContentCachingRequestWrapper request,
ContentCachingResponseWrapper response,
FilterChain filterChain)
throws ServletException, IOException {
LocalDateTime requestProcessingTime = null;
try {
requestProcessingTime = LocalDateTime.now();
filterChain.doFilter(request, response);
} finally {
logRequestAndResponse(request, response, MDC.get(JwtFilter.TRACE_ID), requestProcessingTime);
response.copyBodyToResponse();
}
}
private static ContentCachingRequestWrapper wrapRequest(HttpServletRequest request) {
if (request instanceof ContentCachingRequestWrapper) {
return (ContentCachingRequestWrapper) request;
} else {
return new ContentCachingRequestWrapper(request);
}
}
private static ContentCachingResponseWrapper wrapResponse(HttpServletResponse response) {
if (response instanceof ContentCachingResponseWrapper) {
return (ContentCachingResponseWrapper) response;
} else {
return new ContentCachingResponseWrapper(response);
}
}
}
I have also another filter named JwtFilter whose responsibility is to perform some authentication tasks. In this filter in some where in the code after the doFilter call I need to modify response. When I modify response I got “java.lang.IllegalStateException: getOutputStream() has already been called for this response” error.
@RequiredArgsConstructor
@Slf4j
public class JwtFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(
HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
.....
filterChain.doFilter(request, response);
....
//this is where I modify the response
ResponseEntity<ErrorModel> responseEntity =
globalExceptionHandler.defaultErrorHandler(request, response, e);
response.setStatus(responseEntity.getStatusCodeValue());
response.addHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
response.getWriter().write(objectMapper.writeValueAsString(responseEntity.getBody()));
}
This is the stack trace
java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:572)
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:189)
at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:108)
at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:108)
at javax.servlet.ServletResponseWrapper.getWriter(ServletResponseWrapper.java:108)
at org.springframework.security.web.util.OnCommittedResponseWrapper.getWriter(OnCommittedResponseWrapper.java:156)
at com.innovance.config.security.JwtFilter.handleException(JwtFilter.java:136)
at com.innovance.config.security.JwtFilter.doFilterInternal(JwtFilter.java:114)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
Could you please help me in determining the root of problem and let me know how I can fix it?