XCF引出JAXB
大家知道WebService技术中,客户端与服务端进行通信的媒介是XML,但当你在使用CXF发布与调用WebService时面对的都是java对象,这就需要一种机制在XML格式数据与java对象之间进行转化,即需要做到java对象能够使用XML来合理的展现,并且还能使用XML数据还原回java对象。在CXF中,把这种在XML格式数据与java对象之间相互转化的机制称为数据绑定(DataBindings),CXF支持的数据绑定技术有很多,如:
- Aegis (2.1)
- Aegis Databinding (2.0.x)
- JAXB
- MTOM Attachments with JAXB
- SDO
- XMLBeans
XCF默认使用的是JAXB(2.x),因为这是Java官方推荐的数据绑定技术,在JDK中就直接支持,所以这里就说说JAXB方面的事儿。
JAXB是什么
JAXB是对JSR222(Java Architecture for XML Binding)规范的实现,JAXB是一个业界的标准,是一项可以根据XML Schema产生Java类的技术。该过程中,JAXB提供了将XML实例文档反向生成Java对象树的方法,并能将Java对象树的内容重新写到XML实例文档。从另一方面来讲,JAXB提供了快速而简便的方法将XML模式绑定到Java表示,从而使得Java开发者在Java应用程序中能方便地结合XML数据和处理函数。JAXB还能够使用Jackson对JAXB注解的支持实现(jackson-module-jaxb-annotations),方便生成JSON。如今,JAXB 2.0已是JDK 1.6的组成部分,而JAXB 2.2.3已是JDK 1.7的组成部分。
JAXB使用示例
@XmlRootElement(name="user")
public class User {
private String name = "zhangsan";
private int age = 25;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
@Test
public void test() throws Exception {
JAXBContext context = JAXBContext.newInstance(User.class);
Marshaller marshaller = context.createMarshaller();
User user = new User();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
marshaller.marshal(user, baos);
baos.close();
String xml = new String(baos.toByteArray());
System.out.println(xml);
Unmarshaller unmarshaller = context.createUnmarshaller();
StringReader reader = new StringReader(xml);
Object obj = unmarshaller.unmarshal(reader);
System.out.println(obj);
}
JAXB具体如何使用,可以参看JAXB相关文档,网上有很多,这是里JAXB官方介绍:https://jaxb.java.net/
自定义JAXB转换规则
在CXF使用JAXB进行java对象与XML相互转换时,支持的java数据类型已经有很多,如基本数据类型,JavaBean,List等,但Java对象数据结构千变万化,JAXB也就不可能做到支持所有java数据类型,在碰到不支持的数据类型时需要提供一种让使用者手动扩展的机制,以满足用户需求。例如JAXB默认对Map类型就不支持,但我们可以编写针对Map数据类型的适配器使用JAXB支持该类型,如下:
package com.nightsoul.cxf;
import java.util.Map;
import javax.jws.WebMethod;
import javax.jws.WebService;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@WebService
public interface DemoService {
@WebMethod
@XmlJavaTypeAdapter(XmlMapAdapter.class)Map<String, Object> getValue(@XmlJavaTypeAdapter(XmlMapAdapter.class)Map<String, Object> param);
}
package com.nightsoul.cxf;
import java.util.Map;
public class DemoServiceImpl implements DemoService {
@Override
public Map<String, Object> getValue(Map<String, Object> param) {
return param;
}
}
package com.nightsoul.cxf;
import java.util.Map;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;
public class XmlMapAdapter extends XmlAdapter<String, Map<String, Object>> {
private XStream xStream = new XStream(new DomDriver("UTF-8"));
@Override
public Map<String, Object> unmarshal(String v) throws Exception {
return (Map<String, Object>) xStream.fromXML(v);
}
@Override
public String marshal(Map<String, Object> v) throws Exception {
return xStream.toXML(v);
}
}
在没有使用@XmlJavaTypeAdapter注解对Map<String, Object>类型的参数与返回值类型进行适配前,该WebService是不能正常运行的,加入XmlMapAdapter适配器后,JAXB会使用该配置器的marshal与unmarshal方法完成Map与XML之间的相互转换,其它类型也是如此。