Qwerky
Qwerky

Reputation: 18445

How do I get CXF to understand a Map<String, <List<MyBean>>?

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

Answers (4)

Ahson Imtiaz
Ahson Imtiaz

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

happymeal
happymeal

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

Qwerky
Qwerky

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

jdevelop
jdevelop

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

Related Questions