CXF支持将JSON与rest服务绑定,但需要进行一些最小配置才能使用提供程序。如果您想更好地控制JSON的形式,需要熟悉jettison。请参见
cxf jax-rs json文档了解详细信息。
编辑:根据评论请求,以下是一些代码示例。我对此没有太多经验,但在一个快速测试系统中,以下代码作为示例运行良好。
@GET
@Path ( "test" )
@Produces ( "application/json" )
public Demo getDemo () {
Demo d = new Demo ();
d.id = 1;
d.name = "test";
return d;
}
List providers = new ArrayList ();
JSONProvider jsonProvider = new JSONProvider ();
Map<String, String> map = new HashMap<String, String> ();
map.put ( "http://www.myserviceapi.com", "myapi" );
jsonProvider.setNamespaceMap ( map );
providers.add ( jsonProvider );
TestApi proxy = JAXRSClientFactory.create ( url, TestApi.class,
providers, true );
Demo d = proxy.getDemo ();
if ( d != null ) {
System.out.println ( d.id + ":" + d.name );
}
@XmlRootElement ( name = "demo", namespace = "http://www.myserviceapi.com" )
@XmlType ( name = "demo", namespace = "http://www.myserviceapi.com",
propOrder = { "name", "id" } )
@XmlAccessorType ( XmlAccessType.FIELD )
public class Demo {
public String name;
public int id;
}
备注:
- 提供者列表是您在客户端上配置JSON提供程序的地方。特别是,您可以看到名称空间映射。这需要与您服务器端配置中的内容匹配。我不太了解Jettison选项,因此在操纵控制编组过程的各种旋钮方面没有太多帮助。
- CXF中的Jettison通过将来自JAXB提供程序的XML编组为JSON来工作。因此,您必须确保有效载荷对象都已标记(或以其他方式配置)为应用程序/ xml才能将它们编组为JSON。如果您知道绕过此问题的方法(而不是编写自己的消息体编写器),我很乐意听听。
- 我在服务器上使用spring,因此我的配置都是xml内容。基本上,您需要通过相同的命名空间配置过程将JSONProvider添加到服务中。这方面的代码不方便,但我想它会与客户端方面相当相似。
这个例子有点不完美,但希望能帮助您入门。
编辑2:一个基于xstream的消息体编写器示例,以避免使用jaxb。
@Produces ( "application/json" )
@Consumes ( "application/json" )
@Provider
public class XstreamJsonProvider implements MessageBodyReader<Object>,
MessageBodyWriter<Object> {
@Override
public boolean isWriteable ( Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType ) {
return MediaType.APPLICATION_JSON_TYPE.equals ( mediaType )
&& type.equals ( Demo.class );
}
@Override
public long getSize ( Object t, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType ) {
return -1;
}
@Override
public void writeTo ( Object t, Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, Object> httpHeaders, OutputStream entityStream )
throws IOException, WebApplicationException {
XStream xstream = new XStream ( new JettisonMappedXmlDriver () );
xstream.setMode ( XStream.NO_REFERENCES );
xstream.toXML ( t, entityStream );
}
@Override
public boolean isReadable ( Class<?> type, Type genericType,
Annotation[] annotations, MediaType mediaType ) {
return MediaType.APPLICATION_JSON_TYPE.equals ( mediaType )
&& type.equals ( Demo.class );
}
@Override
public Object readFrom ( Class<Object> type, Type genericType,
Annotation[] annotations, MediaType mediaType,
MultivaluedMap<String, String> httpHeaders, InputStream entityStream )
throws IOException, WebApplicationException {
XStream xstream = new XStream ( new JettisonMappedXmlDriver () );
return xstream.fromXML ( entityStream );
}
}
List providers = new ArrayList ();
XstreamJsonProvider jsonProvider = new XstreamJsonProvider ();
providers.add ( jsonProvider );
TestApi proxy = JAXRSClientFactory.create ( url, TestApi.class,
providers, true );
Demo d = proxy.getDemo ();
if ( d != null ) {
System.out.println ( d.id + ":" + d.name );
}
样例代码缺少对媒体类型支持、错误处理、线程安全等方面的健壮性支持。但是,它应该可以用最少的代码解决jaxb问题。
编辑3 - 样例服务器端配置
正如我之前所说,我的服务器端是经过spring配置的。这是一个可行的样例配置,可以将提供程序连接起来:
<?xml version="1.0" encoding="UTF-8"?>
<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:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/core http://cxf.apache.org/schemas/core.xsd">
<import resource="classpath:META-INF/cxf/cxf.xml" />
<jaxrs:server id="TestApi">
<jaxrs:serviceBeans>
<ref bean="testApi" />
</jaxrs:serviceBeans>
<jaxrs:providers>
<bean id="xstreamJsonProvider" class="webtests.rest.XstreamJsonProvider" />
</jaxrs:providers>
</jaxrs:server>
<bean id="testApi" class="webtests.rest.TestApi">
</bean>
</beans>
我注意到我正在使用的最新版本cxf的媒体类型有所不同,因此上述关于xstream消息正文读取器/写入器的示例需要进行快速修改,其中isWritable/isReadable需要更改为:
return MediaType.APPLICATION_JSON_TYPE.getType ().equals ( mediaType.getType () )
&& MediaType.APPLICATION_JSON_TYPE.getSubtype ().equals ( mediaType.getSubtype () )
&& type.equals ( Demo.class );
编辑4 - 非Spring配置
使用您选择的servlet容器进行配置
org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet
至少有两个初始参数:
jaxrs.serviceClasses
jaxrs.providers
其中,serviceClasses是您想要绑定的服务实现的以空格分隔的列表,例如上面提到的TestApi;providers是消息体提供程序的以空格分隔的列表,例如上面提到的XstreamJsonProvider。在Tomcat中,您可以将以下内容添加到web.xml文件中:
<servlet>
<servlet-name>cxfservlet</servlet-name>
<servlet-class>org.apache.cxf.jaxrs.servlet.CXFNonSpringJaxrsServlet</servlet-class>
<init-param>
<param-name>jaxrs.serviceClasses</param-name>
<param-value>webtests.rest.TestApi</param-value>
</init-param>
<init-param>
<param-name>jaxrs.providers</param-name>
<param-value>webtests.rest.XstreamJsonProvider</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
那基本上是在没有使用spring的情况下最快的运行它的方法。如果您没有使用servlet容器,则需要使用XstreamJsonProvider实例配置JAXRSServerFactoryBean.setProviders,并通过JAXRSServerFactoryBean.setResourceProvider方法设置服务实现。在servlet容器中设置时,请检查CXFNonSpringJaxrsServlet.init方法。这应该可以让您无论什么情况都能开始运行。