users@jersey.java.net

[Jersey] Best practice for returning JSON when using text/plain

From: Tauren Mills <tauren_at_groovee.com>
Date: Mon, 14 Mar 2011 03:57:58 -0700

I'm using a javascript file upload plugin that utilizes an iframe to
upload images in browsers that do not support XMLHTTPRequest uploads
(Internet Explorer and Opera). These browsers will only receive a load
event if the content type is text/plain or text/html, not
application/json. See the bottom of this page for details:
https://github.com/blueimp/jQuery-File-Upload/wiki/Setup

My service layer is creating a MediaDTO object which is represented by
the following JSON:
  {"name":"picture.jpg","type":"image/jpeg","size":"123456789"}

I'm using Jersey with Jackson and my resource works correctly when I
use @Produces(MediaType.APPLICATION_JSON). But unfortunately, I have
to use @Produces(MediaType.TEXT_PLAIN). When I do this, Jersey
complains that it can't find a message body writer (which makes
sense). Here's the code:

@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Produces(MediaType.TEXT_PLAIN)
@Path("image")
public Response uploadFile() {
        DiskFileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload(factory);
                
        try {
                List<FileItem> items = upload.parseRequest(request);
                MediaDTO media = null;
                for (FileItem item : items) {
                        if (!item.isFormField()) {
                                media = fileService.addMemberImage(item);
                                break; // assume we only get one file at a time
                        }
                }
                if (media == null) {
                        return Response.status(Response.Status.BAD_REQUEST).build();
                }
                URI uri = uriInfo.getAbsolutePathBuilder().path(media.getName().toString()).build();
                return Response.created(uri).entity(media).build();
        } catch (FileUploadException e) {
                return Response.status(Response.Status.BAD_REQUEST).build();
        } catch (Exception e) {
                return Response.status(Response.Status.BAD_REQUEST).build();
        }
}

What would be a good way to work around this? I'm considering the following:

1. Having MediaDTO.toJson() create the proper JSON as a string and use:
        return Response.created(uri).entity(media.toJson()).build();

2. Use Jackson ObjectMapper.writeValueAsString():
        String out = objectMapper.writeValueAsString(media);
        return Response.created(uri).entity(out).build();

3. Not use Response as the return type and use String instead in
combination with 1 or 2 above.

These all seem like hacks to me, but I guess I am having to hack
around browser limitations. I'm using option #2 at this time, but is
there some other solution that is better?

Thanks,
Tauren