users@jersey.java.net

Re: [Jersey] Question about polymorphism

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Wed, 12 Aug 2009 08:11:56 +0200

Hi Mike,

Are you using a ContextResolver<JAXBContext> [1] on the server side ?

If so you can explicitly register the same context on the client side.

   ClientConfig cc = new DefaultConfigConfig();
   cc.getClasses().add(MyResolver.class);
   Client c = new Client(cc);

The client side does not not scan for provider classes like the server
side.


If you are not using a ContextResolver<JAXBContext> on the server side
then i am not sure how the marshaling is working :-) i guess it may be
more flexible than unmarshaling.

By default Jersey will create a JAXBContext from the class of the JAXB
bean, and relationships to other beans will be derived from static
references. When polymorphism is utilized there is no static reference
and when unmarshaling JAXB does not know how to unmarshall an element
of the type ”theDerivedOne”. So you need to create a JAXBContext that
declares the other types. For example:

   @Provider
   public class MyResolver implements ContextResolver<JAXBContext> {
     public MyResolver() {
       // Create JAXBContext with the appropriate types or from the
package
     }

     public JAXBContext getContext(java.lang.Class<?> type) {
        if (/type belongs to my set of types/) {
          return /the created JAXBContext/;
        } else {
          return null;
        }
     }
   }

Paul.

[1] https://jsr311.dev.java.net/nonav/javadoc/javax/ws/rs/ext/ContextResolver.html

On Aug 11, 2009, at 9:03 PM, Johnson, Mike (IS) wrote:

> I am just starting to use Jersey. I have a problem with one of my
> methods returning a list of polymorphic objects, and the Jersey
> client API not being able to deserialize them correctly. Here’s my
> situation:
>
> @javax.xml.bind.annotation.XmlType (
>
> name = "theBase",
>
> namespace = ""
>
> )
>
> class TheBase
>
> {
>
> public String getName();
>
> public void setName(String name);
>
> }
>
> @javax.xml.bind.annotation.XmlType (
>
> name = "theDerivedOne",
>
> namespace = ""
>
> )
>
> @javax.xml.bind.annotation.XmlRootElement (
>
> name = "theDerivedOne",
>
> namespace = ""
>
> )
>
> class TheDerivedOne : public TheBase
>
> {
>
> public int getSomeInt ();
>
> public void setSomeInt (int value);
>
> }
>
>
> @javax.xml.bind.annotation.XmlType (
>
> name = "theDerivedTwo",
>
> namespace = ""
>
> )
>
> @javax.xml.bind.annotation.XmlRootElement (
>
> name = " theDerivedTwo ",
>
> namespace = ""
>
> )
>
> class TheDerivedTwo : public TheBase
>
> {
>
> public double getSomeDouble ();
>
> public void setSomeDouble(double value);
>
> }
>
>
>
> My interface has a method that returns a class (let’s call it
> “TheClass”) that holds a List<TheBase> member called “myThings”.
>
> The XML that is generated by Jersey looks correct to me; it
> basically looks like below. Note that each of the “myThings”
> collection members describes its type via its “xsi:type” attribute.
>
>
> <ns2:theClass>
>
> <myThings xsi:type=”theDerivedOne”>
>
> <name>Name One</name>
>
> <someInt>5</someInt>
>
> </myThings>
>
> <myThings xsi:type=”theDerivedTwo”>
>
> <name>Another name</name>
>
> <someDouble>12.1</someDouble>
>
> </myThings>
>
> </ns2:theClass>
>
>
> Now on the client side, I am using the Jersey client API to
> unmarshal a TheClass object from the method. When I do this, the
> objects in the myThings list “lose” their type – they are all of
> type TheBase, with only the Name property available.
>
>
> com.sun.jersey.api.client.Client client =
> com.sun.jersey.api.client.Client.create();
>
> TheClass testInstance = client.resource(baseUrl).get(TheClass.class);
>
>
> Any idea where I am going wrong? Does the jersey unmarshaller
> (which I assume is just the JAXB unmarshaller) support polymorphic
> lists?
>
> Thanks in advance,
>
> Mike Johnson
>
>