[java] CXF: No message body writer found for class - automatically mapping non-simple resources

I am using the CXF rest client which works well for simple data types (eg: Strings, ints). However, when I attempt to use custom Objects I get this:

Exception in thread "main" org.apache.cxf.interceptor.Fault: .No message body writer found for class : class com.company.datatype.normal.MyObject.
    at org.apache.cxf.jaxrs.client.ClientProxyImpl$BodyWriter.handleMessage(ClientProxyImpl.java:523)
    at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:263)
    at org.apache.cxf.jaxrs.client.ClientProxyImpl.doChainedInvocation(ClientProxyImpl.java:438)
    at org.apache.cxf.jaxrs.client.ClientProxyImpl.invoke(ClientProxyImpl.java:177)
    at $Proxy13.execute(Unknown Source)
    at com.company.JaxTestClient.main(JaxTestClient.java:26)
Caused by: org.apache.cxf.jaxrs.client.ClientWebApplicationException: .No message body writer found for class : class com.company.datatype.normal.MyObject.
    at org.apache.cxf.jaxrs.client.AbstractClient.reportMessageHandlerProblem(AbstractClient.java:491)
    at org.apache.cxf.jaxrs.client.AbstractClient.writeBody(AbstractClient.java:401)
    at org.apache.cxf.jaxrs.client.ClientProxyImpl$BodyWriter.handleMessage(ClientProxyImpl.java:515)
    ... 5 more

I'm calling it like this:

JaxExample jaxExample = JAXRSClientFactory.create( "http://localhost:8111/", JaxExample.class );
MyObject before = ...
MyObject after = jaxExample.execute( before );

Here is the method in the interface:

@POST
@Path( "execute" )
@Produces( "application/json" )
MyObject execute( MyObject myObject );

The restlet library does this quite simply, by adding the XStream dependency to your path it "just works". Does CXF something similar?

EDIT #1:

I've posted this as a feature improvement to the CXF issue management system here. I can only hope this will get attended to.

This question is related to java web-services cxf

The answer is


You can also configure CXFNonSpringJAXRSServlet (assuming JSONProvider is used):

<init-param>
  <param-name>jaxrs.providers</param-name>
  <param-value>
      org.apache.cxf.jaxrs.provider.JSONProvider
      (writeXsiType=false)
  </param-value> 
</init-param>

In my scenario, i faced similar error, when the rest url without port number is not properly configured for load balancing. I verified the rest url with portnumber and this issue was not occurring. so we had to update the load balancing configuration to resolve this issue.


Step 1: Add the bean class into the dataFormat list:

<dataFormats>
    <json id="jack" library="Jackson" prettyPrint="true"
          unmarshalTypeName="{ur bean class path}" /> 
</dataFormats>

Step 2: Marshal the bean prior to the client call:

<marchal id="marsh" ref="jack"/>

I encountered this problem while upgrading from CXF 2.7.0 to 3.0.2. Here is what I did to resolve it:

Included the following in my pom.xml

    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-rs-extension-providers</artifactId>
        <version>3.0.2</version>
    </dependency>

    <dependency>
        <groupId>org.codehaus.jackson</groupId>
        <artifactId>jackson-jaxrs</artifactId>
        <version>1.9.0</version>
    </dependency>

and added the following provider

    <jaxrs:providers>
        <bean class="org.codehaus.jackson.jaxrs.JacksonJaxbJsonProvider" />
    </jaxrs:providers>

When programmatically creating server, you can add message body writers for json/xml by setting Providers.

JAXRSServerFactoryBean bean = new JAXRSServerFactoryBean();
bean.setAddress("http://localhost:9000/");

List<Object> providers = new ArrayList<Object>();
providers.add(new JacksonJaxbJsonProvider());
providers.add(new JacksonJaxbXMLProvider());
bean.setProviders(providers);

List<Class< ? >> resourceClasses = new ArrayList<Class< ? >>();
resourceClasses.add(YourRestServiceImpl.class);
bean.setResourceClasses(resourceClasses);

bean.setResourceProvider(YourRestServiceImpl.class, new SingletonResourceProvider(new YourRestServiceImpl()));

BindingFactoryManager manager = bean.getBus().getExtension(BindingFactoryManager.class);
JAXRSBindingFactory restFactory = new JAXRSBindingFactory();
restFactory.setBus(bean.getBus());
manager.registerBindingFactory(JAXRSBindingFactory.JAXRS_BINDING_ID, restFactory);

bean.create();

None of the above changes worked for me. Please see my worked configuration below:

Dependencies:

            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-frontend-jaxrs</artifactId>
                <version>3.3.2</version>
            </dependency>
            <dependency>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-rt-rs-extension-providers</artifactId>
                <version>3.3.2</version>
            </dependency>
            <dependency>
                <groupId>org.codehaus.jackson</groupId>
                <artifactId>jackson-jaxrs</artifactId>
                <version>1.9.13</version>
            </dependency>
            <dependency>
                <groupId>org.codehaus.jettison</groupId>
                <artifactId>jettison</artifactId>
                <version>1.4.0</version>
            </dependency>

web.xml:

     <servlet>
        <servlet-name>cfxServlet</servlet-name>
        <servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
        <init-param>
            <param-name>javax.ws.rs.Application</param-name>
            <param-value>com.MyApplication</param-value>
        </init-param>
        <init-param>
            <param-name>jaxrs.providers</param-name>
            <param-value>org.codehaus.jackson.jaxrs.JacksonJsonProvider</param-value>
        </init-param>
        <init-param>
            <param-name>jaxrs.extensions</param-name>
            <param-value> 
            json=application/json 
        </param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>cfxServlet</servlet-name>
        <url-pattern>/v1/*</url-pattern>
    </servlet-mapping>

Enjoy coding .. :)


If you are using jaxrs:client route of configuring, you can choose to use the JacksonJsonProvider to provide

<jaxrs:client id="serviceId"
    serviceClass="classname"
    address="">
    <jaxrs:providers>
        <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider">
            <property name="mapper" ref="jacksonMapper" />
        </bean>
    </jaxrs:providers>
</jaxrs:client>

<bean id="jacksonMapper" class="org.codehaus.jackson.map.ObjectMapper">
</bean>

You need to include the jackson-mapper-asl and jackson-jaxr artifacts in your classpath


You can try with mentioning "Accept: application/json" in your rest client header as well, if you are expecting your object as JSON in response.


If you are using "cxf-rt-rs-client" version 3.03. or above make sure the xml name space and schemaLocation are declared as below

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:jaxrs="http://cxf.apache.org/jaxrs" 
    xmlns:jaxrs-client="http://cxf.apache.org/jaxrs-client"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd http://cxf.apache.org/jaxrs-client http://cxf.apache.org/schemas/jaxrs-client.xsd">

And make sure the client have JacksonJsonProvider or your custom JsonProvider

<jaxrs-client:client id="serviceClient" address="${cxf.endpoint.service.address}" serviceClass="serviceClass">
        <jaxrs-client:headers>
            <entry key="Accept" value="application/json"></entry>
        </jaxrs-client:headers>
        <jaxrs-client:providers>
            <bean class="org.codehaus.jackson.jaxrs.JacksonJsonProvider">
            <property name="mapper" ref="jacksonMapper" />
        </bean>
        </jaxrs-client:providers>
</jaxrs-client:client>

Examples related to java

Under what circumstances can I call findViewById with an Options Menu / Action Bar item? How much should a function trust another function How to implement a simple scenario the OO way Two constructors How do I get some variable from another class in Java? this in equals method How to split a string in two and store it in a field How to do perspective fixing? String index out of range: 4 My eclipse won't open, i download the bundle pack it keeps saying error log

Examples related to web-services

How do I POST XML data to a webservice with Postman? How to send json data in POST request using C# org.springframework.web.client.HttpClientErrorException: 400 Bad Request How to call a REST web service API from JavaScript? The request was rejected because no multipart boundary was found in springboot Generating Request/Response XML from a WSDL How to send a POST request using volley with string body? How to send post request to the below post method using postman rest client How to pass a JSON array as a parameter in URL Postman Chrome: What is the difference between form-data, x-www-form-urlencoded and raw

Examples related to cxf

Read response body in JAX-RS client from a post request How to log Apache CXF Soap Request and Soap Response using Log4j? CXF: No message body writer found for class - automatically mapping non-simple resources How to avoid the need to specify the WSDL location in a CXF or JAX-WS generated webservice client? JAXB Exception: Class not known to this context Difference between Apache CXF and Axis