users@jersey.java.net

Input and Output binary streams using JERSEY?

From: Tauren Mills <tauren_at_groovee.com>
Date: Mon, 16 Aug 2010 12:07:11 -0700

I just posted a Jersey related question on StackOverflow and then
realized I'd be better off sending it here instead. But if you wish to
answer it, the question is here:
http://stackoverflow.com/questions/3496209/input-and-output-binary-streams-using-jersey

I'm using Jersey to implement a RESTful API that is primarily retrieve
and serve JSON encoded data. But I have some situations where I need
to accomplish the following:

* Export downloadable documents, such as PDF, XLS, ZIP, or other binary files.

* Retrieve multipart data, such some JSON plus an uploaded XLS file

I have a single-page JQuery-based web client that creates AJAX calls
to this web service. At the moment, it doesn't do form submits, and
uses GET and POST (with a JSON request object, not a form post).
Should I utilize a form post to send data and an attached binary file,
or can I create a multipart request with JSON plus binary file? How?

I've been looking through the samples included with Jersey, but
haven't found anything yet that illustrates how to do either of these
things. If it matters, I'm using Jersey with Jackson to do
Object->JSON without the XML step and am not really utilizing JAX-RS.

My application's service layer currently creates a
ByteArrayOutputStream when it generates a PDF file. What is the best
way to output this stream to the client via Jersey? I've created a
MessageBodyWriter, but I don't know how to use it from a Jersey
resource. Is that the right approach?

Here's my writer:

        @Provider
        @Produces("application/pdf")
        public class ExportPDFWriter implements
MessageBodyWriter<ByteArrayOutputStream> {
                @Override
                public void writeTo(ByteArrayOutputStream t, Class<?> type, Type genericType,
                                Annotation[] annotations, MediaType mediaType,
                                MultivaluedMap<String, Object> httpHeaders,
                                OutputStream entityStream) throws IOException,
                                WebApplicationException {
                        
                        entityStream.write(t.toByteArray());
                        
                }

                @Override
                public long getSize(ByteArrayOutputStream t, Class<?> type, Type genericType,
                                Annotation[] annotations, MediaType mediaType) {
                        // Is it possible to output a more accurate size?
                        return -1;
                }

                @Override
                public boolean isWriteable(Class<?> type, Type genericType,
                                Annotation[] annotations, MediaType mediaType) {
                        return true;
                }
        }

But how do I use it in a Resource? What would go into my getPDF method?

        @Inject
        private PDFService pdfService;

        @GET
        @Path("pdf/{id}")
        @Produces("application/pdf")
        public Response getPDF(@PathParam("id") String id) {
                ExportPDFWriter writer;
                ByteArrayOutputStream pdf = pdfService.exportPdf(id);
                // how do I use writer to output my pdf?
                return Response.ok(writer).build();
        }

Thanks for the help!
Tauren