users@jersey.java.net

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

From: Pavel Bucek <pavel.bucek_at_oracle.com>
Date: Tue, 15 Mar 2011 18:23:03 +0100

Hello Tauren,

you can implement your own message body writer for your types - if you
do it, you can keep resource methods simple and return just the object
instance and let message body writer do all the work. Actually, I think
that you should be able just to extend existing JSONObjectProvider (or
that one you are actually using) like this:

     @Produces("*/*")
     @Consumes("*/*")
     @Provider
     public static final class MyJacksonObjectProvider extends
JSONObjectProvider {
         @Override
         protected boolean isSupported(MediaType m) {
             return true;
         }

         @Override
         public boolean isWriteable(Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType) {
             // check for type or whatever you want
             return true || false;
         }
     }

Let me know whether that helped.

Regards,
Pavel


On 03/14/2011 11:57 AM, Tauren Mills wrote:
> 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
>