title: how modify the response body with java filter?
body: <p>I want to perform some filter logic to HTTP responses (which are in json format).</p>
  
  <p>I had successfully change the response body, but when the (string) size of the body changes: I am getting missing the last characters.</p>
  
  <p>To make it simpler, I had created a simple Spring Boot application, with only Web dependency for my rest controller.</p>
  
  <p><strong>My Rest Controller</strong></p>
  
  <pre><code>@RestController
  @RequestMapping("/home/")
  public class RestControllerHome {
  
  @GetMapping (produces=MediaType.APPLICATION_JSON_VALUE)
  public String home() {
          return "{ \"name\" : \"Peter\" }";
    }
  }
  </code></pre>
  
  <p><strong>My Filter</strong></p>
  
  <pre><code>@Component
  public class MyFilter implements Filter {
  
  @Override
  public void destroy() { }
  
  @Override
  public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
  
      HtmlResponseWrapper capturingResponseWrapper = new HtmlResponseWrapper((HttpServletResponse) response);
      filterChain.doFilter(request, capturingResponseWrapper);        
      if (response.getContentType() != null &amp;&amp; response.getContentType().contains("application/json")) {
          String content = capturingResponseWrapper.getCaptureAsString();
  
          // This code works fine
          //response.getWriter().write(content.toUpperCase());
  
          // This code doesn't works because the content size is changed
          response.getWriter().write("{ \"name\" : \"************r\" }");
  
      }
  }
  
  @Override
  public void init(FilterConfig arg0) throws ServletException {  }    
  }
  </code></pre>
  
  <p><strong>HttpServletResponseWrapper</strong>
      // capture the response before it is written</p>
  
  <pre><code>public class HtmlResponseWrapper extends HttpServletResponseWrapper {
  
  private final ByteArrayOutputStream capture;
  private ServletOutputStream output;
  private PrintWriter writer;
  
  public HtmlResponseWrapper(HttpServletResponse response) {
      super(response);
      capture = new ByteArrayOutputStream(response.getBufferSize());
  }
  
  @Override
  public ServletOutputStream getOutputStream() {
      if (writer != null) {
          throw new IllegalStateException("getWriter() has already been called on this response.");
      }
  
      if (output == null) {
          // inner class - lets the wrapper manipulate the response 
          output = new ServletOutputStream() {
              @Override
              public void write(int b) throws IOException {
                  capture.write(b);
              }
  
              @Override
              public void flush() throws IOException {
                  capture.flush();
              }
  
              @Override
              public void close() throws IOException {
                  capture.close();
              }
  
              @Override
              public boolean isReady() {
                  return false;
              }
  
              @Override
              public void setWriteListener(WriteListener arg0) {
              }
          };
      }
  
      return output;
  }
  
  @Override
  public PrintWriter getWriter() throws IOException {
      if (output != null) {
          throw new IllegalStateException("getOutputStream() has already been called on this response.");
      }
  
      if (writer == null) {
          writer = new PrintWriter(new OutputStreamWriter(capture,
                  getCharacterEncoding()));
      }
  
      return writer;
  }
  
  @Override
  public void flushBuffer() throws IOException {
      super.flushBuffer();
  
      if (writer != null) {
          writer.flush();
      } else if (output != null) {
          output.flush();
      }
  }
  
  public byte[] getCaptureAsBytes() throws IOException {
      if (writer != null) {
          writer.close();
      } else if (output != null) {
          output.close();
      }
  
      return capture.toByteArray();
  }
  
  public String getCaptureAsString() throws IOException {
      return new String(getCaptureAsBytes(), getCharacterEncoding());
  }
  
  }
  </code></pre>
  
  <p>In my <strong>doFilter</strong> method, the following code ...</p>
  
  <pre><code>// This code works fine
  response.getWriter().write(content.toUpperCase());
  
  // This code doesn't works because the content size is changed
  //response.getWriter().write("{ \"name\" : \"************r\" }");
  </code></pre>
  
  <p>... gives my the following output : 
  <strong>{"NAME": "PETER"}</strong>
  Which tell me, that the code is working properly.</p>
  
  <p>But, in reality I want to change the body content ...</p>
  
  <pre><code>// This code works fine
  //response.getWriter().write(content.toUpperCase());
  
  // This code doesn't works because the content size is changed
  response.getWriter().write("{ \"name\" : \"************r\" }");
  </code></pre>
  
  <p>... and the previous code, is giving me an incomplete text body as output:
  **{ "name" : "**********</p>
  
  <p>What am I doing wrong? 
  My app have a bigger json body, and a little more complex logic in the filter. But, if I dont get this working I am not being able to make the rest of my code work. Please, help.</p>
  
  <p>I took the Filter and HttpServletResponseWrapper from <a href="https://www.leveluplunch.com/java/tutorials/034-modify-html-response-using-filter/" rel="noreferrer">https://www.leveluplunch.com/java/tutorials/034-modify-html-response-using-filter/</a></p>