users@jersey.java.net

Re: [Jersey] Java generics with Jersey

From: Paul Sandoz <Paul.Sandoz_at_oracle.com>
Date: Thu, 7 Oct 2010 11:29:38 +0200

On Oct 7, 2010, at 11:15 AM, Damiano ALBANI wrote:

> Hello,
>
> I'd like to use Java generics in my JAX-RS project with Jersey, due
> to the way my ExtJS client requires XHR payloads to be formatted.
> Basically, that would consist of a very simple wrapper like:
>
> public class ExtJsWrapper<T> {
> public T rows;
> }
>
> Jersey is able to correctly marshall objects of such type, e.g.:
>
> @GET
> public ExtJsWrapper<Campagne> getCampagne() {
> Campagne campagne = ...
> return new ExtJsListWrapper<Campagne>(campagne);
> }
>
> Works fine, JSON/XML is generated when I fetch the resource by GET.
> Now, I found unmarshalling is a bit trickier, when I need to support
> generics as input parameters:
>
> @PUT
> @Path("{id}")
> public ExtJsWrapper<Campagne>
> updateCampagne(@PathParam("id") int idCampagne,
> ExtJsWrapper<Campagne> wrapper) {
> ...
> }
>
> With JSON, I found that I needed to specified a "type" property,
> otherwise Jersey would fail.
>
> curl -X PUT -H "Content-Type: application/json"
> -d '{ "rows": { "type":"campagne", "id":1, "code":"10-1" } }'
> http://localhost:8080/api/campagnes/2
>
> By the way, what's "funny" is that Jersey is picky about where the
> "type" property lies in the JSON !?
> For instance, this fails:
>
> curl -X PUT -H "Content-Type: application/json"
> -d '{ "rows": { "id":1, "code":"10-1", "type":"campagne" } }'
> http://localhost:8080/api/campagnes/2
>
> So, is there a way to avoid having to specify this type property in
> my JSON (or XML) data?
>

No, because JAXB needs the type information in the document to
correctly determine the XML type to use to unmarshal the data.

When you marshall is the type property included?

In XML this property is an attribute and attributes occur before the
element content. Since JSON has no concept of attributes the
convention here is any properties associated with attributes in the
XML infoset for JAXB need to occur first.

You may want to consider using Jackson instead to avoid these types of
mapping artifacts. Jakub/Tatu can provide more details.


> After a bit of Googling, I've seen references to these 2 classes
> that might help:
> javax.ws.rs.core.GenericEntity<T>
> com.sun.jersey.api.client.GenericType<T>
>
> But how shall I use them in my code?
>
> Finally, I've got another blocking issue, this time with generics in
> the Jersey Client API.
> If I want to call the PUT method as shown above, how can I do it?
>
> I've tried things like:
>
> Campagne campagne = ...
>
> ressource.accept(MediaType.APPLICATION_JSON_TYPE)
> .type(MediaType.APPLICATION_JSON_TYPE)
> .put(new GenericType<ExtJsWrapper<Campagne>>() {},
> campagne);
>
> Also tried playing with all sorts of combinations with GenericEntity/
> GenericType... without success :-(
> I keep on getting this exception:
>
> com.sun.jersey.api.client.ClientHandlerException:
> javax.ws.rs.WebApplicationException: javax.xml.bind.MarshalException
> - with linked exception:
> [javax.xml.bind.JAXBException: class
> fr.univNantes.spin.entities.Campagne nor any of its super class is
> known to this context.]
>

Off list we communicated that you are using a ContextResolver on the
client side. Can you share the code on how you are registering it on
the client side? is it like the following:

https://jersey.dev.java.net/nonav/documentation/latest/user-
guide.html#d0e1925

Paul.