Kevin Duffey wrote:
> Paul,
>
> I think I got it now. Because my XSD isn't putting any XmlRootElement in
> my nodes, I can't parse the object alone.. so the way I am doing it,
> passing in JAXBElement<MyClass> and returning those, is the "only" way I
> can do it based on the output of my XSD at this time.
Just be clear, it was the only way :-) I have modified the things so
that it is possible to use a class annotated with @XmlType for
unmarshalling (parsing) and thus avoid the use of JAXBElement<MyClass>
if you are not interested in the XML root element.
> It may be that the
> XSD could be refactored a bit to generate the XmlRootElement in the
> appropriate class, but not quite sure yet.
But... we should not have to make developers modify the XSD to fit the
"idiosyncrasies" of Jersey :-)
We should try and make things easier out of the box for the common cases
and if necessary utilize JAXB binding features to change what is
produced by XJC.
> However, I am guessing if I
> did this every single API call that sends XML in, or returns XML, even
> small bits of it, would always need to be surrounded by the outer most
> element, that of which would have the @XmlRootElement in it.
>
Any thing that is serialized to an XML document requires that the
serialization process generate an XML root element for the XML document,
otherwise the XML document is not well-formed. This is why you need to
use a JAXB root element bean (because JAXB marshalling knows from this
the XML root element) or a JAXB bean type with JAXBElement<T> so that
the XML root element is supplied to JAXB marshalling.
> Thank you for your quick work. I am not entirely sure what this does for
> me just yet, but I will be playing with it this week and giving you
> feedback.
>
Thanks!
Attached is a simple maven project that exercises all possible
combinations [*] of server/client support of @XmlRootElement, @XmlType
and JAXBElement<T>.
Note that if you switch to using "application/json" there may be some
issues we are currently investigating.
Paul.
[*] Actually not quite all, you can also declare the use of Object for
unmarshalling if and only if you supply a JAXB context with
ContextResolver that returns a JAXB context for Object.
> ----- Original Message ----
> From: Paul Sandoz <Paul.Sandoz_at_Sun.COM>
> To: users_at_jersey.dev.java.net
> Sent: Monday, August 25, 2008 12:28:00 AM
> Subject: Re: [Jersey] How to get JAXB entity in subresource
>
> 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.
>>
>>
>>
>>
>
>
--
| ? + ? = To question
----------------\
Paul Sandoz
x38109
+33-4-76188109