使用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