13

I'm trying to return an image in a JAX-RS web service. I was able to get this successfully working by returning FileInputStream but I'd prefer to avoid creating a File for each request.

I am using Apache CXF and Jackson (all the other resource methods produce application/json).

Code looks like this:

@GET
@Produces("image/png")
public Response getQrCode(@QueryParam("qrtext") String qrtext) {

    ByteArrayOutputStream out = QRCode.from(qrtext).to(ImageType.PNG).stream();

    return Response.ok(out).build();
}

Unfortunately, this produces the dreaded:

org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor:376 - No message body writer has been found for response class ByteArrayOutputStream.

Here's a link to a similar post but it doesn't mention the "No message body writer" issue I'm running into.

I'd appreciate any ideas of how to deal with this issue. Thanks!

Community
  • 1
  • 1
Justin
  • 6,031
  • 11
  • 48
  • 82

2 Answers2

26

Just use StreamingOutput wrapper. For some reason it is unknown, but it is GREAT for providing, well, streaming output. :-)

dpr
  • 10,591
  • 3
  • 41
  • 71
StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • Thanks Tatu. Returning StreamingOutput is preferable to just returning the byte array directly as the Response entity? – Justin Aug 27 '12 at 14:35
  • As usual, "it depends". If you already have `byte[]`, it probably makes no difference. – StaxMan Aug 27 '12 at 18:07
  • 8
    It is usually a bad idea to use toByteArray for streams since this will basically put the entire stream in memory. So if your file is 1GB, you will need at least 1GB in the JVM. If several users are accessing your service, each user will be adding an additional 1GB, which will bring down your server. I always recommend using streams directly. – apanosa Nov 18 '13 at 10:55
10

I think you need to provide an InputStream containing the image in the Response.ok(out) not an OutputStream. (Your JAX-RS framework would read the bytes from the InputStream and put them onto the response, it wouldn't be able to do anything generically with an OutputStream)

(I know you're on CXF, but Jersey's doc: http://jersey.java.net/nonav/documentation/latest/jax-rs.html#d4e324 and by the JAX-RS spec, the framework must provide a MessageBodyWriter for InputStream.)

Edit: You apparently know about InputStreams being required, d'oh... Do you have control over the QRCode class?

Short term, you might be able to do:

return Response.ok(out.toByteArray()).build();
Charlie
  • 7,181
  • 1
  • 35
  • 49