users@jersey.java.net

Re: [Jersey] Jersey Issues with JAXB classes without _at_XmlRootElement - XSD, XJC, Inheritance

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Tue, 06 Oct 2009 09:56:26 +0200

On Oct 6, 2009, at 1:09 AM, Steve Mactaggart wrote:

> Thats how we solve things, we have an Entity object that is the
> element with the data, and then an EntityList which implements
> GenericList<Entity> this way the EntityList can have a strongly
> typed List<Entity> getElements() declared in it, which is also defined
> in the interface to allow us to do generic list things inside the
> resources.
>
> Not sure if this is still best practice, and would love to hear
> thought on it, but it solve our plumbing issues with Jersey.
>

Yes, that works.


It should be possible to support the returning of List<Entity>
directly as long as Entity is annotated with @XmlRootElement e.g.

   @GET
   public List<Entity> get() { ... }

If one needs to return such an instance using Response one can use
GenericEntity:

   @GET
   public Response get() {
     List<Entity> le = ...
     GenericEntity<List<Entity>> entity = new
GenericEntity<List<Entity>>(le) {};
     return Response.ok(entity);
  }

It sucks when switching to Response but we are hitting a restriction
in Java's type system. So if you want to be consistent then it is
better to use a specific type, like you have done with GenericList.

Paul.


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


> On Tue, Oct 6, 2009 at 4:17 AM, Moises Lejter <moilejter_at_gmail.com>
> wrote:
>> Hmm - I just ran into this issue of wanting to return a List<T> ...
>> So - what's the right thing to do in this case? Wrap List<T>
>> inside of a
>> Java class with a single data member, then return that?
>>
>> Moises
>>
>> On Mon, Oct 5, 2009 at 12:03 PM, James Allchin <james_at_knowledgemill.com
>> >
>> wrote:
>>>
>>> Ah OK - thanks Paul... interesting...
>>>
>>> This will certainly help with the GETs. I will give it a go.
>>>
>>> As you point out I will still be affected by GETs with List<T> based
>>> return types.
>>>
>>> I suspect I will also be facing similar issues with POST, PUT, and
>>> DELETE
>>> where I wish to unmarshall the Artifact(s) directly from the XML/
>>> JSON
>>> payload of these methods.
>>>
>>> Thanks,
>>>
>>> James
>>>
>>> -----Original Message-----
>>> From: Paul Sandoz [mailto:Paul.Sandoz_at_Sun.COM]
>>> Sent: Monday, October 05, 2009 10:00 AM
>>> To: users_at_jersey.dev.java.net
>>> Subject: Re: [Jersey] Jersey Issues with JAXB classes without
>>> @XmlRootElement - XSD, XJC, Inheritance
>>>
>>> Hi James,
>>>
>>> I am not sure that annotating Artifact with @XmlRootElement is the
>>> right approach. Because, i presume, when you marshall you want to
>>> the
>>> root element to be that of the concrete type.
>>>
>>> I think Jersey is being too restrictive. Currently the type that is
>>> utilized to analyze whether JAXB can be utilized is the return
>>> type of
>>> the method. I suspect you are doing the following:
>>>
>>> @GET
>>> public Artifact get(...) {
>>> Artifact a = ... // create an instance of EmailArtifact
>>> return a;
>>> }
>>>
>>> Correct?
>>>
>>> Can you try the following workaround:
>>>
>>> @GET
>>> public Response get(...) {
>>> Artifact a = ... // create an instance of EmailArtifact
>>> return Response.ok(a).build();
>>> }
>>>
>>> does the above work?
>>>
>>> If so I need to fix things such that the return type of the method
>>> is
>>> only used if:
>>>
>>> method.getReturnType() != method.getGenericReturnType()
>>>
>>> i.e. we need to utilize the return type of the method say when
>>> returning List<T>.
>>>
>>> Paul.
>>>
>>> On Oct 3, 2009, at 9:56 PM, James Allchin wrote:
>>>
>>>> Hi,
>>>>
>>>> Although not directly related to Jersey - there is a side-effect
>>>> problem caused to Jersey by XSD, XJC and class inheritance. I
>>>> therefore, hope that someone has seen this before...
>>>>
>>>> Essentially, if you have complex types that extend other complex
>>>> types within your XSD, then the resulting base classes do not have
>>>> an @XmlRootElement annotation. This causes problems for Jersey it
>>>> seems because natively we can do GETs PUTs etc against JAXB classes
>>>> that have the @XmlType annotation only (without the
>>>> @XmlRootElement).
>>>>
>>>> I do not want to resort to having to use JAXBElement type methods
>>>> through an ObjectFactory (I have seen this on previous postings).
>>>>
>>>> Has anyone from the group experienced this and solved it (without
>>>> manually adding back in the XmlRootElement annotation to the base
>>>> classes)?
>>>>
>>>> For more information, I have also included the original question
>>>> that I posed on StackOverflow below.
>>>>
>>>> Thanks for any help you can give.
>>>>
>>>> Regards,
>>>>
>>>> James
>>>> ------------------------------
>>>>
>>>> I have a relatively simple XSD file defining my XML schema. The
>>>> complex types within the XSD take advantage of inheritance using
>>>> the
>>>> tags. The problem I having is that I need all complex types to
>>>> generate Java Classes with the @XmlRootElement.
>>>>
>>>> Unfortunately, the way in which XJC generates the classes means
>>>> that
>>>> only derived class gets the @XmlRootElement (not the base class). I
>>>> am using the simple global binding directive to ensure that it
>>>> solves many of the other issues that I have faced with XJC.
>>>>
>>>> Here is an example snippet of the XSD:
>>>>
>>>> <xs:element name="Artifact" type="kmcs:Artifact"/>
>>>> <xs:element name="EmailArtifact" type="kmcs:EmailArtifact"/>
>>>>
>>>> <xs:complexType name="Artifact">
>>>> <xs:sequence>
>>>> <xs:element name="artifactId" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="artifactType" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="contentHash" type="xs:string"
>>>> minOccurs="0"/>
>>>> </xs:sequence>
>>>> </xs:complexType>
>>>>
>>>> <xs:complexType name="EmailArtifact">
>>>> <xs:complexContent>
>>>> <xs:extension base="kmcs:Artifact">
>>>> <xs:sequence>
>>>> <xs:element name="subject" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="threadSubject" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="from" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="to" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="cc" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="bcc" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="messageId" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="date" type="xs:date"
>>>> minOccurs="0"/>
>>>> <xs:element name="size" type="xs:long"
>>>> minOccurs="0"/>
>>>> <xs:element name="hasAttachment" type="xs:boolean"
>>>> minOccurs="0"/>
>>>> <xs:element name="sensitivity" type="xs:string"
>>>> minOccurs="0"/>
>>>> <xs:element name="headerHash" type="xs:string"
>>>> minOccurs="0"/>
>>>> </xs:sequence>
>>>> </xs:extension>
>>>> </xs:complexContent>
>>>> </xs:complexType>
>>>>
>>>> As we can see from the above snippet, EmailArtifact extends
>>>> Artifact.
>>>>
>>>> The java class code for EmailArtifact contains the following:
>>>>
>>>> @XmlAccessorType(XmlAccessType.FIELD)
>>>> @XmlType(name = "EmailArtifact", propOrder = {
>>>> "subject",
>>>> "threadSubject",
>>>> "from",
>>>> "to",
>>>> "cc",
>>>> "bcc",
>>>> "messageId",
>>>> "date",
>>>> "size",
>>>> "hasAttachment",
>>>> "sensitivity",
>>>> "headerHash"
>>>> })
>>>> @XmlSeeAlso({
>>>> ExtendedEmail.class
>>>> })
>>>> @XmlRootElement(name = "EmailArtifact")
>>>> public class EmailArtifact
>>>> extends Artifact
>>>> {
>>>>
>>>> protected String subject;
>>>> protected String threadSubject;
>>>> protected String from;
>>>> protected String to;
>>>> protected String cc;
>>>> protected String bcc;
>>>> protected String messageId;
>>>> @XmlSchemaType(name = "date")
>>>> protected XMLGregorianCalendar date;
>>>> protected Long size;
>>>> protected Boolean hasAttachment;
>>>> protected String sensitivity;
>>>> protected String headerHash;
>>>>
>>>> The java class code for Artifact contains the following:
>>>>
>>>> @XmlAccessorType(XmlAccessType.FIELD)
>>>> @XmlType(name = "Artifact", propOrder = {
>>>> "artifactId",
>>>> "artifactType",
>>>> "contentHash"
>>>> })
>>>> @XmlSeeAlso({
>>>> ManagedDocArtifact.class,
>>>> EmailArtifact.class
>>>> })
>>>> public class Artifact {
>>>>
>>>> protected String artifactId;
>>>> protected String artifactType;
>>>> protected String contentHash;
>>>>
>>>> In the EmailArtifact we can see that it contains the
>>>> @XmlRootElement
>>>> but the base type Artifact does not contain @XmlRootElement.
>>>>
>>>> How can you force XJC to generate @XmlRootElement for all classes
>>>> including the base types.
>>>>
>>>> Thanks,
>>>>
>>>> James
>>>>
>>>>
>>>> ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>>
>>>
>>>
>>>
>>> ---------------------------------------------------------------------
>>> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
>>> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>>>
>>
>>
>> --
>> This message has been scanned for viruses and
>> dangerous content by MailScanner, and is
>> believed to be clean.
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: users-unsubscribe_at_jersey.dev.java.net
> For additional commands, e-mail: users-help_at_jersey.dev.java.net
>