问题描述
Apache CXF是一个比较成熟的Java版Web Service框架,我们当前的项目中正在使用。它当然支持RESTful风格的Web Service,也支持JSON的数据格式。但是,在最新的3.0.4版本中,却无法自动将数据转换为JSON格式。
像下面这样发布一个HelloWorld服务的话,是可以成功的。但是对于需要转换JSON数据的场景(通过JAXB方式或其他),它会报出错误。
package com.tech4j.demo;
import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
import com.tech4j.demo.webservice.HelloWorld;
import com.tech4j.demo.webservice.HelloWorldImpl;
public class CxfJsonProviderDemo {
public static void main(String[] args) {
HelloWorld hello = new HelloWorldImpl();
JAXRSServerFactoryBean factory = new JAXRSServerFactoryBean();
factory.setResourceClasses(HelloWorld.class);
factory.setResourceProvider(HelloWorld.class,
new SingletonResourceProvider(hello));
String address = "http://localhost:9000/MyService";
factory.setAddress(address);
factory.create();
}
}
在这段代码中,HelloWorld
接口定义了一个getPerson()
方法,它返回一个Person
类型的对象,并且使用@Produces
注解声明其为JSON格式的数据。具体接口和实现类的代码略。
如果通过浏览器访问地址http://localhost:9000/MyService/HelloWorld/getPerson
,页面会提示说“No message body writer has been found for class com.tech4j.demo.webservice.Person, ContentType: application/json”。虽然服务发布成功,但是却无法将Person
类型的对象转换为JSON数据。
解决方案
这是由于新版本的CXF中已经不再提供默认的JSON Provider了,我们需要自己找一个第三方的Provider,设置给CXF框架,它才能够自动调用该Provider完成转换操作。
我们需要在发布服务的时候,为CXF的服务factory设置这个第三方的Provider,例如Jackson。代码如下:
JacksonJaxbJsonProvider jaxbProvider = new JacksonJaxbJsonProvider();
factory.setProvider(jaxbProvider);
这样一来,CXF就会自动调用这个Provider来完成符合JAXB标准的对象与JSON格式的转换工作。
Maven信息
Apache CXF
CXF框架当前最新的Maven构建信息如下(可根据实际需要扩充或修改):
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>3.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.0.4</version>
</dependency>
SLF4J-Log4j
CXF默认不含有日志记录的组件,需要手动再引入SLF4J和/或Log4j的Maven依赖。如下所示:
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.10</version>
</dependency>
JacksonJsonProvider
Jackson专门针对JAX-RS标准提供了JSON Provider,其Maven信息如下:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.5.2</version>
</dependency>
参考代码
HelloWorld.java
package com.tech4j.demo.webservice;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
@Path("/HelloWorld")
public interface HelloWorld {
@GET
@Path("/getPerson")
@Produces(MediaType.APPLICATION_JSON)
public Person getPerson();
}
HelloWorldImpl.java
package com.tech4j.demo.webservice;
public class HelloWorldImpl implements HelloWorld {
@Override
public Person getPerson() {
return new Person("JavaHuan", 24);
}
}
Person.java
package com.tech4j.demo.webservice;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement
public class Person {
private String name;
private Integer age;
public Person() {
}
public Person(String name, Integer age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
Person
类中含有JAXB的注解配置,如@XmlRootElement
。还可以添加其他的JAXB注解。