users@jersey.java.net

Re: [Jersey] How to get JAXB entity in subresource

From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
Date: Mon, 25 Aug 2008 09:28:00 +0200

Hi Kevin,

There are two kinds of JAXB beans:

   1) JAXB root element beans whose classes are annotated with
@XmlRootElement. These correspond to XSD
       elements; and

   2) JAXB type beans whose classes are annotated with @XmlType.
These correspond to XSD types.

Depending on how things are defined in a schema XJC may generate only
of 2) and provide methods in the Object factory that return
JAXBElement<T>.

For unmarshalling the JAXB unmarshaller can be supplied with a JAXB
context that supports 1) or 2). If an XML type bean is returned by
the unmarshaller then the root element of the XML document will be
processed but that root element information will not be associated
with the JAXB type bean. Or if the root element is required to be
known for 2) then it is necessary to obtain a JAXBElement instance
for the JAXB bean type using a specific method on the JAXB unmarshaller.

For marshalling it is required that JAXB have enough information to
create a well formed XML document. Thus JAXB root element beans can
be marshalled but JAXB type beans cannot, because it does not have a
XML root element associated with it. In this case an instance of
JAXBElement<T> needs to be used.

Jersey has supported 1) using JAXB root element bean instances and
types and supported 2) using JAXBElement<T> instances and types where
T is a JAXB type bean. However i have just added support for 2) in
the trunk for unmarshalling (consuming) such that a JAXB type bean
class can be referenced directly. This also solves for you the Client
API issue.

As for the other issues, i think i am going to write a stand alone
sample application for you that exercises various JAXB use cases and
will help you understand what is going on and the best way to
implement you services.

Paul.


On Aug 24, 2008, at 6:44 PM, Kevin Duffey wrote:

> Hey all,
>
> Two problems I am trying to figure out: First is how to "consume" a
> put/post body of xml in the subresource class:
>
> @Path("/path")
> class MyClass {
>
> @GET
> @Produces("application/xml")
> public Response get(){
> return Response.ok().build();
> }
>
> @Path("{page}")
> public MySubClass getSubResource(@PathParam("page") String page){
> return new MySubClass(page);
> }
> }
>
>
>
> class MySubClass {
> @PUT
> @Consumes("application/xml")
> public Response update(JAXBElement<MyJaxBGenClass> mjbgc) {
> }
> }
>
> The problem is, everything I've tried, I am not seeing the
> MyJaxBGenClass getting passed to the subresource class. I've tried
> consuming on the getSubResource, tried using the JAXBElement
> parameter in the getSubResource() method itself. Every where I put
> the @Consumes and the JAXBElement parameter, it fails.
>
>
> Second problem, which is "similar" to the first.. why do I have to
> use JAXBElement<MyJAXBClass> instead of MyJAXBClass in a method
> signature? :
>
> @GET
> @Produces({"application/xml", "text/xml", "application/json"})
> public Response find(JAXBElement <MyJAXBGenClass> myclass){
> }
>
> The above always tells me it can't find a BodyReader fo the
> MyJAXBGenClass. Yet, it's generated with XJC and has the JAXB
> annotations in the XSD that generates the classes. Now, if Paul
> recalls, there is an issue on the Jersey Client where by the
> terminating method can not handle a JAXB Class directly. I am
> wondering if the same thing is happening here. For some reason my
> JAXB generated classes do not have an @XmlRootElement anywhere. Not
> even the "root" class. I am using the Ant XJC taskdef to generate
> these, so maybe I am not passing in a param to XJC that I should
> be? At any rate, I've seen some of the sample code that uses the
> JAXB generated classes directly in the method signuature:
>
> @GET
> @Produces("application/xml")
> public Response find(MyJAXBGenClass myclass){
> }
>
> @PUT
> @Consumes("appluication/xml")
> public Response update(MyJAXBGenClass myclass){
> }
>
>
> So the above code should work, right? I shouldn't need to do any
> special JAXB stuff to turn the JAXBElement into an actual object?
> Right now, every method I use I have something like:
>
> @GET
> @Produces("application/xml")
> public Response find(){
> MyJAXBClass mc = new MyJAXBClass();
> mc.set....
>
> JAXBElement<MyClass> v = new ObjectFactory().createMyClass(mc);
> return Response.ok(v).build();
> }
>
> and the reverse:
>
> @PUT
> @Consumes("application/xml")
> public Response update(JAXBElement<MyClass> mc){
> MyClass m = (MyClass)mc.getValue();
> }
>
>
> So.... I don't know why I have to keep doing it that way when some
> of the examples, the JAXBJSon one specifically show the actual
> class itself in the method as if the JAXB/Jersey knows how to
> handle it without me needing to do any JAXB getValue() or
> ObjectFactory.createClass() stuff.
>
> I even copied the @Producer class from the sample, called
> JAXBContextResolver, and put my classes in there and it's still not
> working. I don't even know if that resolver class is required. But
> from my understanding using JAXB generated classes, the Annotations
> in the generated classes are all that Jersey needs to be able to do
> the JAXB conversions for me. I just seem to be missing something.
>
> Thanks.
>
>
>
>