Returning a binary file from REST service

You might want to return a binary file such as image or pdf from a REST service, if thats the case then JAX-RS provides you with 3 options. I wanted to try those options to i did create a sample application, that you can download from here. I did create a HelloBinaryService.java file which is a resource class that has 3 methods in each of these methods i am reading a static image file from c:/temp and returning it

package com.webspherenotes.rest;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.StreamingOutput;

@Path("/hellobinary")
public class HelloBinaryService {

  @GET
  @Path("/file")
  @Produces("image/png")
  public File getFile(){
    File samplePDF = new File("c:/temp/distributedmap.png");
    return samplePDF;
  }

  @GET
  @Path("/fileis")
  @Produces("image/png")
  public InputStream getFileInputStream()throws Exception{
    FileInputStream fileIs = new FileInputStream("c:/temp/distributedmap.png");
    return fileIs;
  }

  @GET
  @Path("/fileso")
  @Produces("image/png")
  public StreamingOutput getFileStreamingOutput() throws Exception{
    
    return new StreamingOutput() {
      
      @Override
      public void write(OutputStream outputStream) throws IOException,
          WebApplicationException {
        FileInputStream inputStream = new FileInputStream("c:/temp/distributedmap.png");
        int nextByte = 0;
        while((nextByte  = inputStream.read()) != -1 ){
          outputStream.write(nextByte);
        }
        outputStream.flush();
        outputStream.close();
        inputStream.close();
      }
    };
  }
  
}
The first and easiest option would be to return a object of java.io.File directly and the JAX-RS will figure out how to read the file and return binary content of the file, but you cannot use this option if your returning a file that is not stored on the file system. Second option would be to return object of InputStream, in that case the InputStream could be pointing to file on local system or file stored in database or something like that, in this case JAX-RS container will figure out how to return bytes from InputStream and return it The last option would be to return object of StreamingOutput, this gives you most flexibility in this case JAX-RS container will give you control at the time of writing body of the message, this is little more work for you since you have to take care of reading the bytes from InputStream and write into output stream but then you get chance to compress the content,....

6 comments:

Anonymous said...

Do you know if, in the case of returning an InputStream, the InputStream is closed when all the data is read?

Sunil Patil said...

This depends on container implementation but i believe it should close the InputStream

rajeshblog said...

I tried 3rd snippet by removing produce line. and im sending StreamingOutput object (it contains zip file data ) - - so iam getting follwing error... help me ASAP
com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java type, interface javax.ws.rs.core.StreamingOutput, and MIME media type, text/html, was not found

tho tran said...

excellent

Anonymous said...

FYI, Inpustream are closed automatically by the MessageBodyWriter. This does not depend on the container implementation.

@Override
public void writeTo(
InputStream t,
Class type,
Type genericType,
Annotation annotations[],
MediaType mediaType,
MultivaluedMap httpHeaders,
OutputStream entityStream) throws IOException {
try {
writeTo(t, entityStream);
} finally {
t.close();
}
}

Leslie Lim said...

I read your blog.I thought it was great.. Hope you have a great day. God bless.

Rica
www.imarksweb.org