You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Mickael Marrache <Mi...@xconnect.net> on 2012/10/12 11:44:21 UTC

XmlRootElement annotation and marshalling error

Hi,

I'm working on a REST web service. In my WADL, I've defined only one resource B where I define multiple possible operations on B (GET, PUT, DELETE...). I also import in my WADL, a XML schema where B is declared using a complexType but without defining a root element. After generating my code using WADL2Java plugin, I get the resource interface of B and the classes generated from my schema. As expected, the class B (corresponding to the complexType B) is not annotated with @XmlRootElement. So, when I call the GET method on a given resource of type B, I get an error since the resource can't be marshaled.

I've looked on the web for a solution and I've found this blog http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html. It seems that the solution is to create JAXBElement's that wrap my B instances. But, I don't understand how it works in the context of a REST service.

Here's my WADL:

<?xml version="1.0"?>
<application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
            xsi:schemaLocation="http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd"
            xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://wadl.dev.java.net/2009/02"
            xmlns:srvcb="com:mycomp:service:base">

            <grammars>
                        <schema xmlns="http://www.w3.org/2001/XMLSchema"
                                   targetNamespace="com:mycomp:service:rest">
                                   <import namespace="com:mycomp:service:base"
                                               schemaLocation="schema.xsd" />
                        </schema>
            </grammars>

            <resources base="REPLACE_WITH_THE_BASE_URL">
                        <resource id="BResource" path="/B/{id}">
                                   <method id="getB" name="GET">
                                               <request>
                                                           <param name="id" style="template" type="xsd:string" />
                                               </request>
                                               <response status="200">
                                                           <representation mediaType="application/xml" element="srvcb:BType" />
                                               </response>
                                   </method>
                        </resource>
            </resources>
</application>

I get the following interface:

@Path("/B/{id}")
public interface BResource {

    @GET
    @Produces("application/xml")
    BType getB(@PathParam("id") String id);

}

I don't understand how can I create a JAXBElement that wraps my BType's instance and also, how all of this works in this context. The getB method returns an instance of BType, not a JAXBElement instance. I'm confused.

Thanks,
Mickael

Re: XmlRootElement annotation and marshalling error

Posted by Sergey Beryozkin <sb...@gmail.com>.
Hi
On 12/10/12 10:44, Mickael Marrache wrote:
> Hi,
>
> I'm working on a REST web service. In my WADL, I've defined only one resource B where I define multiple possible operations on B (GET, PUT, DELETE...). I also import in my WADL, a XML schema where B is declared using a complexType but without defining a root element. After generating my code using WADL2Java plugin, I get the resource interface of B and the classes generated from my schema. As expected, the class B (corresponding to the complexType B) is not annotated with @XmlRootElement. So, when I call the GET method on a given resource of type B, I get an error since the resource can't be marshaled.
>
> I've looked on the web for a solution and I've found this blog http://blog.bdoughan.com/2012/07/jaxb-and-root-elements.html. It seems that the solution is to create JAXBElement's that wrap my B instances. But, I don't understand how it works in the context of a REST service.
>
> Here's my WADL:
>
> <?xml version="1.0"?>
> <application xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
>              xsi:schemaLocation="http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd"
>              xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://wadl.dev.java.net/2009/02"
>              xmlns:srvcb="com:mycomp:service:base">
>
>              <grammars>
>                          <schema xmlns="http://www.w3.org/2001/XMLSchema"
>                                     targetNamespace="com:mycomp:service:rest">
>                                     <import namespace="com:mycomp:service:base"
>                                                 schemaLocation="schema.xsd" />
>                          </schema>
>              </grammars>
>
>              <resources base="REPLACE_WITH_THE_BASE_URL">
>                          <resource id="BResource" path="/B/{id}">
>                                     <method id="getB" name="GET">
>                                                 <request>
>                                                             <param name="id" style="template" type="xsd:string" />
>                                                 </request>
>                                                 <response status="200">
>                                                             <representation mediaType="application/xml" element="srvcb:BType" />
>                                                 </response>
>                                     </method>
>                          </resource>
>              </resources>
> </application>
>
> I get the following interface:
>
> @Path("/B/{id}")
> public interface BResource {
>
>      @GET
>      @Produces("application/xml")
>      BType getB(@PathParam("id") String id);
>
> }
>
> I don't understand how can I create a JAXBElement that wraps my BType's instance and also, how all of this works in this context. The getB method returns an instance of BType, not a JAXBElement instance. I'm confused.
>
At the moment, if you have @XmlType annotated classes in the signature, 
then CXF JAXBElementProvider needs to be explicitly configured to be 
marshalled (and unmarshalled) as JAXBElements, for example:

<bean id="jaxbProvider" 
class="org.apache.cxf.jaxrs.provider.JAXBElementProvider">
  <property name="marshalAsJaxbElement" value="true"/>
</bean>

...

<jaxrs:providers>
   <ref bean="jaxbProvider"/>
</jaxrs:providers>

Glen has raised this issue recently and perhaps we should make 
@XmlType-classes auto-wrapped. One potential problem with auto-wrapping 
is that the representation is not guaranteed to match the schema.

For example, suppose you have

<xs:element name="theBar" type="tns:bar"/>
<xs:complexType name="bar">
...
</xs:complexType>

and

@GET
public Bar getBar() {}

There's no way auto-wrapping will guess that the name of the root 
element has to be "theBar".

I think I've just convinced myself that we should not do auto-wrapping :-)

So, please configure JAXBElementProvider as suggested above, and 
additionally, consider adding a jaxbElementClassNames map property 
(class name: key, expected root element name - value) to make sure the 
representation matches the schema.

Alternatively, update the schema to use anonymous types - that will get 
@XmlRootElement added. Yet another option is to configure jaxb plugin to 
do it - I think I saw someone doing it,


HTH, Sergey

> Thanks,
> Mickael
>


-- 
Sergey Beryozkin

Talend Community Coders
http://coders.talend.com/

Blog: http://sberyozkin.blogspot.com