2

I am logging the request body if some custom exception occurs. For this, I have added a filter which caches the HttpServletRequest object using the ContentCachingRequestWrapper. Here is the code sample for that:

@Component
public class RequestWrapperFilter extends OncePerRequestFilter {

  @Override
  protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
    filterChain.doFilter(new ContentCachingRequestWrapper(httpServletRequest), httpServletResponse);
  }

}

And, my controller class looks something like this:
@PostMapping(Paths.INSPECTION_IMAGE_SUBMIT_REQUEST_V1)
  public ResponseEntity<ResponseObject> processThisRequest(
    @RequestBody RequestObject requestObject //how am I able to access this requestObject?
  ) throws Exception {
    return someService.process(requestBody);
  }

So, how am I able to use this requestObject? Since, in the filter class, I have cached this, therefore, the getReader() method must have already been called on this, right? So I should not be able to read the requestObject, right?

Ankit Arora
  • 110
  • 3
  • 16

2 Answers2

2

======EDIT======

Look at how ContentCachingRequestWrapper works

javax.servlet.http.HttpServletRequest wrapper that caches all content read from the input stream and reader, and allows this content to be retrieved via a byte array.

Cached does not mean it read the input stream and save in memory, but whenever bytes is read from the wrapped stream, the cacher will write same bytes to its internal buffer.

So your requestObject is only read once in the entire filter chain, when you create the ContentCachingRequestWrapper in your filter, it does not cache anything yet.

Other part of framework will read the cached content by invoking the ContentCachingRequestWrapper#getContentAsByteArray method (not read from the stream again, as it already read). (Note that the content only available after the body reader finish reading the input stream, if you invoke before, you will receive incomplete data)

======END EDIT======

Can use RequestBodyAdviceAdapter


@ControllerAdvice
public class RequestAdvice extends RequestBodyAdviceAdapter {
    
    @Override
    @Nonnull
    public Object afterBodyRead(@Nonnull Object body, @Nonnull HttpInputMessage inputMessage,
        @Nonnull MethodParameter parameter, @Nonnull Type targetType,
        @Nonnull Class<? extends HttpMessageConverter<?>> converterType) {
        
        // Do something with the payload
        return super.afterBodyRead(body, inputMessage, parameter, targetType, converterType);
    }
}
Mạnh Quyết Nguyễn
  • 17,677
  • 1
  • 23
  • 51
  • Hi @Mạnh Quyết Nguyễn. Thank you for the answer but I want to understand how my current code is working. Shouldn't the controller throw an exception since I have already read the request body in the content cache? – Ankit Arora Dec 21 '20 at 12:01
0

Try this solution . As long as you are passing wrappedRequest (as mentioned in this link) object ahead for filter chain, you can read requestObject in your controller.

Kiran Bhagwat
  • 574
  • 1
  • 6
  • 13
  • In the solution link posted above, the same problem should arise, i.e., request body should be null because it is already read by contnet caching in the filter? My doubt is, how is my solution working since I have already read the request body in the content caching before it reaches my controller? – Ankit Arora Dec 21 '20 at 06:51