使用JAX-WS创建web service时,大部分对象都能通过JAXB序列化成xml,包括基本的java类型、普通的javabean、list,数组等。那么对于JAXB 不知道如何处理的一些类型需要编写一个适配器,该适配器继承javax.xml.bind.annotation.adapters.XmlAdapter<ValueType,BoundType>抽象类。
XmlAdapter类型参数:
BoundType
- JAXB 不知道如何处理的一些类型。编写一个适配器,以便允许通过ValueType 将此类型用作内存表示形式。ValueType
- JAXB 无需其他操作便知道如何处理的类型XmlAdapter方法:
XmlAdapter.marshal(...):编组过程中,JAXB 绑定框架调用 XmlAdapter.marshal(..) 将 bound 类型修改为 value 类型,然后将 value 类型编组为 XML 表示形式。XmlAdapter.unmarshal(...):解组过程中,JAXB 绑定框架首先将 XML 表示形式解组为 value 类型,然后调用
XmlAdapter.unmarshal(..) 将 value 类型修改为 bound 类型。
下面以Date对象说明如何自定义序列化的适配器
默认情况下,Java 绑定规则模式将Date 绑定到 XmlGregorianCalendar,现在我们将Date对象直接序列化成string的表示形式:
//实现适配器 public class DateXmlAdapter extends XmlAdapter<String, Date> { @Override public String marshal(Date v) throws Exception { SimpleDateFormat fmt=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); return fmt.format(v); } @Override public Date unmarshal(String v) throws Exception { SimpleDateFormat fmt=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); return fmt.parse(v); } }
@XmlAccessorType(XmlAccessType.FIELD)
public class UserInfo implements Serializable
{
private int id;
private String userName;
//适配器注解
@XmlJavaTypeAdapter(DateXmlAdapter.class)
private Date birthday;
public int getId()
public void setId(int id)
public String getUserName()
public void setUserName(String userName)
public Date getBirthday()
public void setBirthday(Date birthday)
}
这样就完成了转换。这里要注意的是XmlJavaTypeAdapter是注解在元素上而不是方法上,如果形参是Date类型应该是setBirthday(@XmlJavaTypeAdapter(DateXmlAdapter.class) Date myDate)
JAXB 中传递是不支持接口的,所以不能直接传递map对象,CXF默认是使用JAXB 序列化对象的所以也是不支持传递map对象的。
通常会有IllegalAnnotationException java.util.Map is an interface, and JAXB can't handle interfaces这样的异常提示。那么根据上面的原理,我们需要自定义一个适配器来解决这个问题。
首先定义一个web service接口,定义了两个方法一个是返回Map<String, UserInfo>,另一个接收Map<String, UserInfo>参数
@WebService public interface IQueryUser { @XmlJavaTypeAdapter(value=UserMapAdapter.class) Map<String, UserInfo> getUserMap(); void setUserMap(@XmlJavaTypeAdapter(value=UserMapAdapter.class) @WebParam(name="userMap")Map<String, UserInfo> userMap); }
这里需要模拟一个Map类:
@XmlType(name="UserMap") @XmlAccessorType(XmlAccessType.FIELD) public class UserMap { private List<UserEntry> entries = new ArrayList<UserEntry>(); public List<UserEntry> getEntries() { return entries; } public void addEntry(UserEntry entry) { entries.add(entry); } public static class UserEntry { private String key; private UserInfo users; public UserEntry() { } public UserEntry(String key, UserInfo users) { this.key = key; this.users = users; } public UserEntry(Map.Entry<String, UserInfo> entry) { this.key = entry.getKey(); this.users = entry.getValue(); } public String getKey() { return key; } public void setKey(String key) { this.key = key; } public UserInfo getUsers() { return users; } public void setUsers(UserInfo users) { this.users = users; } } }
实现适配器
public class UserMapAdapter extends XmlAdapter<UserMap, Map<String, UserInfo>> { @Override public UserMap marshal(Map<String, UserInfo> v) throws Exception { UserMap uMap=new UserMap(); for (Map.Entry<String, UserInfo> element : v.entrySet()) { uMap.addEntry(new UserMap.UserEntry(element)); } return uMap; } @Override public Map<String, UserInfo> unmarshal(UserMap v) throws Exception { List<UserMap.UserEntry> lstEntry=v.getEntries(); Map<String, UserInfo> uMap=new HashMap<String,UserInfo>(); for (UserMap.UserEntry userEntry : lstEntry) { uMap.put(userEntry.getKey(), userEntry.getUsers()); } return uMap; } }
使用工具生成客户端代理类后,客户端调用代码如下:
JaxWsProxyFactoryBean soapFactoryBean = new JaxWsProxyFactoryBean();
soapFactoryBean.setAddress("http://localhost:8080/WebServiceDemo/queryuser");
soapFactoryBean.setServiceClass(IQueryUser.class);
IQueryUser queryService = (IQueryUser) soapFactoryBean.create();
UserMap uMapWrapper = queryService.getUserMap();//取得map
List<UserEntry> userList = uMapWrapper.getEntries();
for (UserEntry userEntry : userList)
{
System.out.println(userEntry.key + " " + userEntry.users.getUserName());
}
queryService.setUserMap(uMapWrapper);//传入map