title: Spring MVC Jsonp filter incorrect response. (Content length cuts of response output)
body: <p>I'm trying to implement this <a href="http://jpgmr.wordpress.com/2010/07/28/tutorial-implementing-a-servlet-filter-for-jsonp-callback-with-springs-delegatingfilterproxy/" rel="nofollow" title="Jsonp Filter">Jsonp Filter</a>.<br />
  However, whenever I call my url <code>/server/api.jsonp?callback=something</code> it cuts of the last part of the response (ContentLength has the length of the original response output. In this case that would be 15 since <code>{test: 'blaat'}</code> is my original response output - see Controller).<br />atleast this is what I assume since the output I get is <code>test({test: 'bl</code>. Does someone know how to get the filter to work and send the correct response back?
  (I even try to force the Content-length - see JsonpCallbackFilter)</p>
  
  <p>Filter:</p>
  
  <pre><code>public class JsonpCallbackFilter implements Filter {
  
      protected final Log logger = LogFactory.getLog(JsonpCallbackFilter.class);
  
      @Override
      public void init(FilterConfig fConfig) throws ServletException {
      }
  
      @Override
      public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
          HttpServletRequest httpRequest = (HttpServletRequest) request;
          HttpServletResponse httpResponse = (HttpServletResponse) response;
  
          Map&lt;String, String[]&gt; params = httpRequest.getParameterMap();
  
          if (params.containsKey("callback")) {
              if (logger.isDebugEnabled()) {
                  logger.debug("Wrapping response with JSONP callback: " + params.get("callback")[0]);
              }
  
              OutputStream out = httpResponse.getOutputStream();
  
              GenericResponseWrapper wrapper = new GenericResponseWrapper(httpResponse);
  
              chain.doFilter(request, wrapper);
  
              byte[] callBack = (params.get("callback")[0] + "(").getBytes();
              byte[] callBackEnd = (");").getBytes();
  
              byte[] jsonpResponse = new byte[callBack.length + wrapper.getData().length + callBackEnd.length];
              System.arraycopy(callBack, 0, jsonpResponse, 0, callBack.length);
              System.arraycopy(wrapper.getData(), 0, jsonpResponse, callBack.length, wrapper.getData().length);
              System.arraycopy(callBackEnd, 0, jsonpResponse, callBack.length + wrapper.getData().length, callBackEnd.length);
  
              logger.debug(new String(jsonpResponse));
              logger.debug("Length: " + jsonpResponse.length);
  
              out.write(jsonpResponse);
  
              wrapper.setContentType("text/javascript;charset=UTF-8");
              wrapper.setContentLength(jsonpResponse.length);
          } else {
              if (logger.isDebugEnabled()) {
                  logger.debug("No callback found, resort to default json request!");
              }
              chain.doFilter(request, response);
          }
      }
  
      @Override
      public void destroy() {
      }
  }
  </code></pre>
  
  <p>Generic Response Wrapper:</p>
  
  <pre><code>public class GenericResponseWrapper extends HttpServletResponseWrapper {
  
      private ByteArrayOutputStream output;
      private FilterServletOutputStream filterStream;
      private PrintWriter printWriter;
      private int contentLength;
      private String contentType;
  
      public GenericResponseWrapper(HttpServletResponse response) {
          super(response);
  
          output = new ByteArrayOutputStream();
          filterStream = new FilterServletOutputStream(output);
          printWriter = new PrintWriter(output, true);
      }
  
      public byte[] getData() {
          printWriter.close();
          return output.toByteArray();
      }
  
      @Override
      public ServletOutputStream getOutputStream() {
          return filterStream;
      }
  
      @Override
      public PrintWriter getWriter() {
          return printWriter;
      }
  
      public int getContentLength() {
          return contentLength;
      }
  
      @Override
      public void setContentLength(int length) {
          this.contentLength = length;
          super.setContentLength(length);
      }
  
      @Override
      public String getContentType() {
          return contentType;
      }
  
      @Override
      public void setContentType(String contentType) {
          this.contentType = contentType;
          super.setContentType(contentType);
      }
  }
  </code></pre>
  
  <p>Custom Filter outputstream:</p>
  
  <pre><code>public class FilterServletOutputStream extends ServletOutputStream {
  
      private DataOutputStream stream;
  
      public FilterServletOutputStream(OutputStream output) {
          stream = new DataOutputStream(output);
      }
  
      @Override
      public void write(int b) throws IOException {
          stream.write(b);
      }
  
      @Override
      public void write(byte[] b) throws IOException {
          stream.write(b);
      }
  
      @Override
      public void write(byte[] b, int off, int len) throws IOException {
          stream.write(b, off, len);
      }
  }
  </code></pre>
  
  <p>web.xml filter mapping:</p>
  
  <pre><code>&lt;filter&gt;
      &lt;filter-name&gt;jsonpCallbackFilter&lt;/filter-name&gt;
      &lt;filter-class&gt;org.springframework.web.filter.DelegatingFilterProxy&lt;/filter-class&gt;
  &lt;/filter&gt;
  &lt;filter-mapping&gt;
      &lt;filter-name&gt;jsonpCallbackFilter&lt;/filter-name&gt;
      &lt;url-pattern&gt;*.jsonp&lt;/url-pattern&gt;
  &lt;/filter-mapping&gt;
  </code></pre>
  
  <p>bean mapping in applicationContext.xml</p>
  
  <pre><code>&lt;bean id="jsonpCallbackFilter" class="com.world2.utils.spring.filters.jsonp.JsonpCallbackFilter" /&gt;
  </code></pre>
  
  <p>Controller:</p>
  
  <pre><code>@Controller
  public class ApiRequests {
      protected final Logger logger = Logger.getLogger(ApiRequests.class);
  
      @RequestMapping(value = "api.json", produces = {"application/json"}, method = RequestMethod.GET)
      @ResponseBody
      public String handleActionJson(final HttpServletRequest request){
          return "{test: 'blaat'}";
      }
  
      @RequestMapping(value = "api.jsonp", produces = {"text/javascript", "application/javascript", "application/json"}, method = RequestMethod.GET)
      @ResponseBody
      public String handleActionJsonp(final HttpServletRequest request){
          return "{test: 'blaat'}";
      }
  }
  </code></pre>
  
  <p>Url I try to call:</p>
  
  <pre><code>http://host:8084/MyProject/server/api.jsonp?callback=test&amp;_=1364980436087
  </code></pre>
  
  <p>Debug output:</p>
  
  <pre><code>11:13:57,776 DEBUG JsonpCallbackFilter:57 - test({test: 'blaat'});
  11:13:57,776 DEBUG JsonpCallbackFilter:58 - Length: 22
  </code></pre>
  
  <p>Result:</p>
  
  <pre><code>test({test: 'bl
  </code></pre>
  
  <p>instead of expected result:</p>
  
  <pre><code>test({test: 'blaat'});
  </code></pre>