Reputation: 18445
My restful method returns a Map<String,List<MyBean>>
but I can't figure out how to get CXF and JAXB to serialise this as XML.
I want it to look something like this (although I'm not all that bothered how it is serialised so long as it works on both sides);
<response>
<items key="a">
<item>
....
</item>
<item>
....
</item>
</items>
<items key="b">
<item>
....
</item>
</items>
</response>
If I just return a Map
I get;
[org.apache.cxf.jaxrs.interceptor.JAXRSOutInterceptor] No message body writer has been found for response class HashMap.
If I try and use a wrapper object I get;
[org.apache.cxf.jaxrs.provider.AbstractJAXBProvider] java.util.List is an interface, and JAXB can't handle interfaces.
Any suggestions? Is this just a CXF issue (I'm using version 2.3.2)? I'm sure I've had a similar thing working in Jersey.
Upvotes: 3
Views: 10519
Reputation: 181
You can provide the configuration for msg-handlers/providers as follows if you are using CXF 2.3.2 with Spring:
<jaxrs:server id="restContainer" address="/">
<jaxrs:serviceBeans>
<ref bean="yourRestfulServiceBeanId"/>
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml"/>
</jaxrs:extensionMappings>
<jaxrs:providers>
<ref bean="jaxbXmlProvider"/>
</jaxrs:providers>
</jaxrs:server>
<!-- Webservice message handlers -->
<bean id="jaxbXmlProvider" class="org.apache.cxf.jaxrs.provider.JAXBElementProvider">
<property name="jaxbElementClassMap" ref="propertiesMap"/>
</bean>
<util:map id="propertiesMap">
<entry key="jaxb.formatted.output">
<value type="java.lang.Boolean">true</value>
</entry>
</util:map>
The handler will see the JAXB annotations and generate the required output.
Upvotes: 0
Reputation: 1413
the error occurred because CXF does not know what are the keys and what are the objects. you will need to use aegis to specify the java Map to XML bindings.
refer to the section "Handling Maps" in this link: xfire mapping and collections. (i couldn't find the aegis Map/Collection documentation for CXF so here's the documentation from xfire instead. the aegis configuration should be similar since xfire 2.0 is CXF)
alternatively, just stick to Collections and Lists.
Upvotes: 1
Reputation: 18445
There's nothing like some time away from the screen to clear one's mind. I figured this out over lunch and the answer is not to use a Map
at all, but a List
of List
wrappers.
@XmlRootElement
public class MyResponse {
private List<ItemListWrapper> items;
//getters and setters
}
@XmlType
public class ItemListWrapper {
private String key;
private List<Item> items;
@XmlAttribute
public String getKey() {
return this.key;
}
//rest of the getters and setters
}
@XmlType
public class Item {
//just a bean
}
Upvotes: 3
Reputation: 12296
Why not to try to use some concrete implementation of List? Or create your own marshaller which will try to understand what kind of list you're dealing with.
http://fusesource.com/docs/esb/4.3.1/cxf_interceptors/CXFInterceptorIntro.html
http://cxf.apache.org/custom-cxf-transport.html
Upvotes: 0