users@jersey.java.net

Re: [Jersey] Unable to serialize (JAXB) when returning Response instead of actual object types

From: Craig McClanahan <Craig.McClanahan_at_Sun.COM>
Date: Fri, 14 Nov 2008 13:49:20 -0800

Jeremy Whitlock wrote:
> Hi All,
> While working on my example for serializing collections to JSON
> and XML, I ran into a problem. (Using JAXB support built into jersey
> and jersey-json of course.) Basically, I wanted to have one method
> return two different content types. It was suggested yesterday to use
> the ResponseBuilder and return a Response object instead of the actual
> entity object(s). It has worked fine until now. Basically, I have the
> following:
>
> @GET
> @Path("people.{format}")
> public List<Person> getPeople(@PathParam("format") String format) {
> // return Response.ok(people).type(formats.get(format)).build();
> return people;
> }
>
> With the current approach, I only get JSON serialization since there is
> no way to tell Jersey that I want to change the return format. If I
> update the method to return a Response instead of the List<Person>, JAXB
> tells me that there is no content writer for java.util.ArrayList. It
> appears that when returning a JAXB-formatted response, your methods
> cannot return a Response object and must return the entity, or list of
> entities. If that is the case, then the suggestion to use a
> ResponseBuilder is flawed and I need a working way to tell the response
> what format to use without using Response objects. If that is not the
> case, what am I doing wrong or what have I uncovered?
>
>
I'll bet you are running into an "interesting" detail about JAXB that
also bit me.

I generate my JAXB classes from a schema with embedded JAXB annotation
stuff, and (to make a long story short), JAXB does *not* generate a
@XmlRootElement annotiation (I *think* that's the right one). Without
this annotation, JAXB has no way to know what "outer" element to use
around your list. The workaround is a little verbose but it does work:

@GET
@Path("people.{format]")
public Response getPeople(@PathParam("format") String format) {
  List<Person> people = ...; // Your logic to gather the list
  JAXBElement entity = new JAXBElement(new QName("people"),
    People.class, GlobalScope.class, people);
  return Response.ok(entity).type(formats.get(format)).build();
}

where "People" is a class that has a List<Person> property. I think
there's a way to do this kind of thing without needing the extra class
and will have to figure that one out.

You'll need to do a similar sort of thing if you have a method that
returns a single Person as well.

Sorry I didn't grok that you were also using JAXB in my initial response.
> Take care,
>
> Jeremy Whitlock | Software Engineer | CollabNet, Inc.
> 8000 Marina Blvd. Suite 600 | Brisbane, CA 94005 | USA
> O 650.228.2516 | C 970.988.8822 | jwhitlock_at_collab.net
>
>
Craig