CXF+JAXB处理复杂数据

CXF默认使用JAXB 来实现对象和XML之间的映射。在前面的例子 中,使用CXF发布的Webservice,其方法的参数和返回值都是简单类型。 本文讨论对象复杂性的分级,验证对于各种复杂度JAXB的支持情况,以及使用JAXB时对于Map,循环引用,继承等情况的处理办法。 文中的例子没有直接调用JAXB的API,而是用CXF发布webservice的形式验证对象到xml的marshal和unmarshal, 所以本文也可以作为使用CXF的参考资料。

Table of Contents

  • 1 数据复杂性的分类

    • 1.1 简单数据类型
    • 1.2 自定义类型
    • 1.3 集合类型
    • 1.4 复杂类型
  • 2 JAXB对数据复杂性的支持
  • 3 常用技巧
    • 3.1 使用自定义的XmlAdapter支持Map
    • 3.2 断开循环引用的回路
    • 3.3 使用@XmlSeeAlso标注处理继承关系
  • 4 代码
    • 4.1 maven工程文件:pom.xml
    • 4.2 Map适配器:MapAdapter.java
    • 4.3 Map适配器使用的key-value结构:MapEntity.java
    • 4.4 JavaBean:User.java
    • 4.5 JavaBean:MyUser.java
    • 4.6 服务接口定义:CXFDemo.java
    • 4.7 服务实现类:CXFDemoImpl.java
    • 4.8 测试代码:TestEndpoint.java

1 数据复杂性的分类

大体来说,Java中的数据/数据对象按照其复杂度可以分为以下几类:

1.1 简单数据类型

包括基本类型和Java对基本类型的封装,主要有:

基本类型 封装类
float Float
double Double
byte Byte
short Short
int Integer
long Long
char Character
boolean Boolean
char[] String

1.2 自定义类型

在C里面叫做struct,在Java里面叫做JavaBean,包含自定义属性和getter/setter方法。

1.3 集合类型

Java的集合类(Collection)主要分为List,Set,Map三个系列。List实现了元素的序列(顺序),Set实现不重复的集合,Map实现了key-value的映射。

1.4 复杂类型

更复杂的情况是对于上述三种类型的组合运用,比如在自定义类型中使用集合,或者集合的嵌套等。 复杂类型还会涉及到循环引用和继承关系等问题。

2 JAXB对数据复杂性的支持

  • 简单类型

对于简单的数据类型,JAXB不需要任何处理就完全能够支持

  • 自定义类型

JAXB对于一般的JavaBean也能够支持,比如下面的例子:

User.java

public class User {private Integer id;private String name;public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}
}

不需要JavaBean实现Serializable接口,也不需要增加@XmlRootElement声明。

  • 集合类型

    JAXB能够内置支持List和Set集合,但是对于Map的支持需要自己处理。

  • 复杂类型

    JAXB支持简单类型、自定义类型、集合类型等的嵌套,但是对于循环引用、继承等情况需要增加额外的处理。

3 常用技巧

3.1 使用自定义的XmlAdapter支持Map

JAXB可以在变量上添加@XmlJavaTypeAdapter标注,指定对该变量专门的适配器进行处理。 适配器继承XmlAdapter类,并覆盖了marshal和unmarshal方法,分别用于对象到XML的映射和XML到对象的映射。

使用XmlAdapter可以实现对Map类型的映射。

比如对于要通过CXF发布的WebService接口方法上,可以增加标注:

@XmlJavaTypeAdapter(MapAdapter.class)
Map<String,User> getUserMap();Integer setUserMap(@XmlJavaTypeAdapter(MapAdapter.class)Map<String,User> users);

其中的MapAdapter就是自己实现的Map适配器,代码如下:

MapAdapter.java

MapEntity是自己定义的一个简单结构,用于保持Map中的key-value关系:

MapEntity.java

public class MapEntity{public Object key;public Object value;
}

经过这样的处理,就能够实现Map与XML之间的映射。

3.2 断开循环引用的回路

对象之间的引用很有可能出现回路。最简单的情况是两个对象之间互相引用。这在ORM中很常见。如果我们在前面的User类中增加父子关系,如下:

User.java

当同时在两个方向设置引用关系时,就发生了循环引用:

child.parent = parent;
parent.children.put(child.getName(), child);

发生循环引用时,JAXB就会抛出异常。而处理的办法就是断开其中一个方向的引用。具体做法就是使用@XmlTransient标注,表明该属性在marshal是不作处理。 如上面的User中,我们可以只处理parent到child的引用,而不处理child到parent的引用:

@XmlTransient
public User parent;

这样虽然解决了循环引用的问题,但是会导致得到User对象的parent属性为null。为使用带来不变。 解决的办法是在JavaBean中增加afterUnmarshal()方法,当JAXB从xml恢复出对象后,会自动调用这个方法。我们可以在方法中将丢失的信息补全:

afterUnmarshal方法

public void afterUnmarshal(Unmarshaller u,Object parent) {for(Iterator itor = this.children.values().iterator();itor.hasNext();){User user = (User)itor.next();user.parent = this;}
}

3.3 使用@XmlSeeAlso标注处理继承关系

继承关系在ORM中已经处理得非常完善了,JAXB处理继承关系更加简单,只需要在继承树的根类上增加@XmlSeeAlso标注,声明所有的子类即可。 比如我们定义了一个User的子类:

public class MyUser extends User {...}

则只需要在User类上面增加标注:

@XmlSeeAlso

@XmlSeeAlso({MyUser.class
})
public class User {...}

4 代码

本文相关的所有代码如下:

4.1 maven工程文件

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.hysec</groupId><artifactId>cxfdemo</artifactId><packaging>jar</packaging><version>1.0-SNAPSHOT</version><name>cxfdemo</name><dependencies><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.apache.cxf</groupId><artifactId>apache-cxf</artifactId><version>2.4.1</version><type>pom</type></dependency></dependencies>
</project>

4.2 Map适配器

MapAdapter.java

package com.hysec.utils.jaxb;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;import javax.xml.bind.annotation.adapters.XmlAdapter;public class MapAdapter extends XmlAdapter<MapEntity[], Map> {@Overridepublic MapEntity[] marshal(Map map) throws Exception {// TODO Auto-generated method stubMapEntity[] list = new MapEntity[map.size()];Set keyset = map.keySet();int index =0;for(Iterator itor=keyset.iterator();itor.hasNext();){MapEntity item = new MapEntity();item.key = itor.next();item.value = map.get(item.key);list[index++] = item;            }return list;}@Overridepublic Map unmarshal(MapEntity[] list) throws Exception {// TODO Auto-generated method stubMap map = new HashMap();for(int i=0;i<list.length;i++){MapEntity item = list[i];map.put(item.key, item.value);}return map;}}

4.3 Map适配器使用的key-value结构

MapEntity.java

package com.hysec.utils.jaxb;public class MapEntity{public Object key;public Object value;
}

4.4 JavaBean父类

User.java

package cxfdemo;import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;@XmlSeeAlso({MyUser.class
})
public class User {private Integer id;private String name;@XmlTransient public User parent;public Map<String,User> children = new HashMap<String,User>();public Integer getId() {return id;}public void setId(Integer id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public void afterUnmarshal(Unmarshaller u,Object parent) {for(Iterator itor = this.children.values().iterator();itor.hasNext();){User user = (User)itor.next();user.parent = this;}}}

4.5 JavaBean子类

MyUser.java

package cxfdemo;public class MyUser extends User {public String myProp;
}

4.6 webservice接口定义

CXFDemo.java

package cxfdemo;import java.util.List;
import java.util.Map;
import java.util.Set;import javax.jws.WebService;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;import com.hysec.utils.jaxb.MapAdapter;@WebService
public interface CXFDemo {String sayHello(String foo);String sayHelloToUser(User user);User getUser(String name);List<User> getUsers();Integer setUsers(List<User> users);Set<User> getUserSet();Integer setUserSet(Set<User> users);@XmlJavaTypeAdapter(MapAdapter.class)     Map<String,User> getUserMap();Integer setUserMap(@XmlJavaTypeAdapter(MapAdapter.class)Map<String,User> users);User addChild(User parent,User child);
}

4.7 webservice实现类

CXFDemoImpl.java

package cxfdemo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;import javax.jws.WebService;@WebService()
public class CXFDemoImpl implements CXFDemo {public String sayHello(String foo) {return "hello "+foo;}public String sayHelloToUser(User user){return "hello "+user.getName();}public User getUser(String name){User user = new User();user.setName(name);return user;}public List<User> getUsers(){List<User> users = new ArrayList<User>();users.add(new User());return users;}public Integer setUsers(List<User> users){return users.size();}public Set<User> getUserSet(){Set<User> set = new HashSet<User>();set.add(new User());set.add(new User());return set;}public Integer setUserSet(Set<User> users){return users.size();}public Map<String,User> getUserMap(){HashMap<String,User> map = new HashMap<String,User>();User user1 = new User();user1.setName("Holbrook");map.put("Holbrook", user1);User user2 = new User();user2.setName("wanghaikuo");map.put("wanghaikuo", user2);return map;}public Integer setUserMap(Map<String,User> users){return users.size();}public User addChild(User parent,User child){child.parent = parent;parent.children.put(child.getName(), child);return parent;}
}

4.8 测试用例

TestEndpoint.java

package cxfdemo.test;import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;import javax.xml.ws.Endpoint;import junit.framework.Assert;
import junit.framework.TestCase;import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;import cxfdemo.CXFDemo;
import cxfdemo.CXFDemoImpl;
import cxfdemo.MyUser;
import cxfdemo.User;public class TestEndpoint extends TestCase {private static final String ADDRESS = "http://localhost:9000/cxfdemo"; private static CXFDemo service;@Overrideprotected void setUp() throws Exception {// TODO Auto-generated method stubsuper.setUp();if(null==service){System.out.println("Starting Server");  CXFDemoImpl demo = new CXFDemoImpl();  Endpoint.publish(ADDRESS, demo);System.out.println("Start success");JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();factory.setServiceClass(CXFDemo.class);factory.setAddress(ADDRESS);service = (CXFDemo)factory.create();}}public void testSayHello(){Assert.assertEquals(service.sayHello("foo"), "hello foo");}public void testSayHelloToUser(){User user = new User();user.setName("Holbrook");String result = service.sayHelloToUser(user);Assert.assertEquals(result,"hello Holbrook");}public void testGetUser(){User user = service.getUser("Holbrook");Assert.assertEquals("Holbrook",user.getName());}public void testGetUsers(){List<User> users = service.getUsers();Assert.assertEquals(1,users.size());}public void testSetUsers(){List<User> users = new ArrayList<User>();users.add(new User());users.add(new User());users.add(new User());Assert.assertEquals(3,service.setUsers(users).intValue());}public void testGetUserSet(){Set<User> userSet = service.getUserSet();Assert.assertEquals(2,userSet.size());}public void testSetUserSet(){Set<User> set = new HashSet<User>();set.add(new User());set.add(new User());Assert.assertEquals(2, service.setUserSet(set).intValue());}public void testGetUserMap(){Map<String,User> map = service.getUserMap();Assert.assertTrue(map.containsKey("Holbrook"));Assert.assertTrue(map.containsKey("wanghaikuo"));}public void testSetUserMap(){HashMap<String,User> map = new HashMap<String,User>();User user1 = new User();user1.setName("Holbrook");map.put("Holbrook", user1);User user2 = new User();user2.setName("wanghaikuo");map.put("wanghaikuo", user2);Assert.assertEquals(2, service.setUserMap(map).intValue());}public void testAddChild(){User root = new User();root.setName("root");//root.parent = root;
        User child = new User();child.setName("child");User parent = service.addChild(root, child);Assert.assertTrue(parent.children.containsKey("child"));Assert.assertEquals(parent.children.get("child").parent, parent);}public void testInheritance(){User parent = new User();MyUser child = new MyUser();child.setName("child");child.myProp = "subclass Prop";User root = service.addChild(parent, child);User newChild = root.children.get("child");System.out.println(newChild instanceof MyUser);System.out.println(((MyUser)newChild).myProp);}}

Date: 2012-12-14 23:39:13 CST

Author: Holbrook

Org version 7.8.11 with Emacs version 24

Validate XHTML 1.0

CXF+JAXB处理复杂数据相关推荐

  1. JAXWS CXF JAXB + MyEclipse + Maven Byron自學視頻04

    JAXWS CXF JAXB + MyEclipse + Maven Byron自學視頻04 Description: 使用 Apache CXF 搭配 wsdl2java + JAXB 調用 Web ...

  2. Java与C#平台通信 WCF CXF SOAP

    问题提出 : 采用的方案 : 基于 C#平台的 SOA框架 ---WCF简介 WCF 平台搭建 JAVA 调用 WCF 基于 Java平台的 SOA框架 ---CXF简介 CXF平台搭建 CXF 框架 ...

  3. CXF框架的一些问题

    2019独角兽企业重金招聘Python工程师标准>>> 去官网下载CXF框架(我当期的版本是apache-cxf-3.0.15), 配置环境变量:①CXF_HOME=D:\javas ...

  4. CXF的webservice接口中字符串参数中文问题

    为什么80%的码农都做不了架构师?>>>    22162][WARN][main] 10:51:45,122 method:org.apache.cxf.common.loggin ...

  5. 使用JAXB将XML Schema绑定到Java类

    http://blog.csdn.net/zsyspace/article/details/1786079 Java Architecture for XML Binding (JAXB) 是一项可以 ...

  6. Android开发中调用Spring CXF整合发布的WebService接口为什么抛出异常错误?

    摘要:最近在协助同事搞Android调用WebService接口,再测试的过程中发现老师报错,经过baidu,google,终于解决了,现在记录一下: 一:错误信息: 2015-10-28 18:50 ...

  7. Spring 5.X+CXF 3.X 开发SOAP Web Service Client客户端实例

    服务接口, 可以使用soapui产生 @WebService(targetNamespace = "http://service.demo.ws.osxm.com/") publi ...

  8. Spring 5.X+CXF 3.X 开发SOAP Web Service服务端实例

    方式1:使用 jaxws:server 步骤1. 定义返回的Model POJO的定义, 最好是加上默认构造函数.服务端不加不会出错, 但是在客户端调用的时候类似的Model定义不加默认构造函数会出错 ...

  9. unwinding now org.apache.cxf.interceptor.Fault: Marshalling Error: null

    1.异常描述 2019-04-19 16:11:30.486 [org.apache.cxf.phase.PhaseInterceptorChain]-[WARN] Interceptor for { ...

最新文章

  1. MySQL 配置数据库编码
  2. 2021揭东一中今年高考成绩查询入口,2021年揭阳高考状元是谁分数多少分,历年揭阳高考状元名单...
  3. 首届Elastic社区技术大会隆重开幕!腾讯分享2场中文演讲
  4. H3C通过端口ID决定端口角色
  5. Xshell配置ssh免密码登录-密钥公钥(Public key)
  6. java 可视化_可视化Java 9模块关系
  7. 在Windows系统下搭建ELK日志分析平台
  8. android:contentDescription 的用途
  9. QT多线程,使用串口接收数据通过UDP端口进行数据转发
  10. vue项目启动后,页面显示空白
  11. ActiveX开发详解
  12. IPTV的开展在广电企业、电信运营商角度上的异同
  13. 在html标签中写alert,文本不会写入页面,但会显示在alert()消息中。 JavaScript和HTML...
  14. SQL字符串转化数字
  15. Gensim库生成与导入W2V模型_CodingPark编程公园
  16. 2345流氓软件让浏览器打开跳转到它的导航,并且自动下载安装2345浏览器
  17. 浙江理工大学校园网DNS性能测试脚本
  18. 深度学习——人工神经网络中为什么ReLu要好过于tanh和sigmoid function?
  19. Java基础再回首之设计模式系列①-----StrategyPattern 策略者模式(案列教程,附带demo)
  20. android 切凹凸图,Android实现边缘凹凸的View

热门文章

  1. 电气期刊论文实现:基于遗传优化的非侵入式居民负荷分解方法(有代码)
  2. MATLAB机器学习系列-8 极限学习机(Extreme Learning Machine, ELM)原理及其代码实现
  3. VTK:Cell Edge Neighbors用法实战
  4. OpenCASCADE:Inspector的TInspectorEXE 示例
  5. OpenCASCADE绘制测试线束:拓扑命令之复杂拓扑
  6. OpenCASCADE:OCCT应用框架OCAF之函数机制使用示例
  7. OpenCASCADE:下载安装
  8. boost::get_deleter相关的测试程序
  9. boost::multiprecision模块实现导入/导出 cpp_int 的位 到 8 位无符号值的向量相关的测试程序
  10. boost::hana::overload用法的测试程序