Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey/JAX-RS : Return Content-Length in response header instead of chunked transfer encoding

I'm using Jersey to create RESTful API resources, and ResponseBuilder to generate the response.

Example code for the RESTful resource:

public class infoResource{
  @GET
  @Path("service/{id}")
  @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
  public Response getCompany(@PathParam("id")String id) {
      //company is just a POJO.
      Company company = getCompany(id);
      return Response.status(200).entity(company).build();  
  }
}

In the response, it's returning chunked transfer encoding in the response headers. What is the proper way in the "Jersey world" to have it return the Content-Length header instead of the Transfer-Encoding: chunked header in the response headers?

like image 302
richsinn Avatar asked Jul 25 '12 22:07

richsinn


3 Answers

Selecting Content-Length or Transfer-Encoding is just those Containers choice. It's really a matter of buffer size.

One possible solution is providing a SevletFilter which buffers all those marshalled bytes and sets Content-Length header value.

See this page.

@WebFilter
public class BufferFilter implements Filter {

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
        throws IOException, ServletException {

        final ByteArrayOutputStream buffer =
            new ByteArrayOutputStream();

        // prepare a new ServletResponseWrapper
        // which returns the buffer as its getOutputStream();

        chain.doFilter(...)

        // now you know how exactly big is your response.

        final byte[] responseBytes = buffer.toByteArray();
        response.setContentLength(responseBytes.length);
        response.getOutputStream().write(responseBytes);
        response.flush();
    }

    @Override
    public void destroy() {
    }
}
like image 146
Jin Kwon Avatar answered Oct 10 '22 17:10

Jin Kwon


In you class that extends ResourceConfig you can set the buffer size. Responses above this size will be chunked, below will have Content-Length.

public class ApplicationConfig extends ResourceConfig {

  public ApplicationConfig() {
    //your initialization
    property(CommonProperties.OUTBOUND_CONTENT_LENGTH_BUFFER, 2000000); 
  }
}
like image 28
MGH Avatar answered Oct 10 '22 17:10

MGH


For example, if your inputstream is read from a local file system, just add:

response.header( "Content-Length", file.length() );

Check the full code for a clearer explanation:

@Path("/files")
public class FileDownloadService {

    private static final String TXT_FILE = "C:\\your file";    
    @GET
    @Path("/txt")
    @Produces(MediaType.APPLICATION_OCTET_STREAM)
    public Response getTextFile() throws IOException {
        File file = new File(TXT_FILE);
        FileInputStream inStream = new FileInputStream(file);
        ResponseBuilder response = Response.ok((Object) inStream);
        response.header("Content-Disposition", "attachment; filename=\"filename\"");
        response.header( "Content-Length", file.length() );
        return response.build();
    }  
}

The client side is a Apache HttpClient code.

like image 40
Octavian Ionel Avatar answered Oct 10 '22 18:10

Octavian Ionel