在CXF中用JAXB数据绑定支持HashMap类型
SOAP中不支持HashMap,但可以通过适配器将数组转换成HashMap的方式来支持。
这是通过JAXB2.0中一个适配器类来转换的,先看下这个类的说明:
javax.xml.bind.annotation.adapters
类 XmlAdapter<ValueType,BoundType>
java.lang.Object
javax.xml.bind.annotation.adapters.XmlAdapter<ValueType,BoundType>
- 类型参数:
-
BoundType
- JAXB 不知道如何处理的一些类型。编写一个适配器,以便允许通过 ValueType 将此类型用作内存表示形式。 -
ValueType
- JAXB 无需其他操作便知道如何处理的类型。
这样,我们先定义一个用来传送数据的通用数组,包含了KEY和VALUE两个成员用来存MAP的项:
public
class
OtherValues
{
public OtherValues () {};
public OtherValues (String key, String value) {
this.key = key;
this.value = value;
};
public String key;
public String value;
}
public OtherValues () {};
public OtherValues (String key, String value) {
this.key = key;
this.value = value;
};
public String key;
public String value;
}
再定义一个转换类:(数组到HashMap的转换)
import
java.util.HashMap;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class OtherValuesAdapter extends XmlAdapter < OtherValues[], HashMap < String,String >> {
static Logger logger = Logger.getLogger (OtherValuesAdapter.class.getName());
public HashMap<String, String> unmarshal(OtherValues[] value ) {
logger.error("unmarshal begin");
HashMap<String, String> r = new HashMap<String,String>();
for( OtherValues c : value )
r.put(c.key, c.value);
return r;
}
public OtherValues[] marshal( HashMap<String,String> value ) {
logger.error("marshal begin");
OtherValues[] pairs = new OtherValues[value.size ()];
int i = 0;
for(Entry<String,String> entry : value.entrySet()) {
pairs[i++] = new OtherValues (entry.getKey(), entry.getValue());
}
return pairs;
}
}
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class OtherValuesAdapter extends XmlAdapter < OtherValues[], HashMap < String,String >> {
static Logger logger = Logger.getLogger (OtherValuesAdapter.class.getName());
public HashMap<String, String> unmarshal(OtherValues[] value ) {
logger.error("unmarshal begin");
HashMap<String, String> r = new HashMap<String,String>();
for( OtherValues c : value )
r.put(c.key, c.value);
return r;
}
public OtherValues[] marshal( HashMap<String,String> value ) {
logger.error("marshal begin");
OtherValues[] pairs = new OtherValues[value.size ()];
int i = 0;
for(Entry<String,String> entry : value.entrySet()) {
pairs[i++] = new OtherValues (entry.getKey(), entry.getValue());
}
return pairs;
}
}
我们需要在一个结构中来包含使用HashMap的变量,因为必须为这个变量再声明一个 @XmlJavaTypeAdapter,这样JAXB才会在收到相应消息时调用我们的转换类。这是结构定义:
import
java.util.HashMap;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class MapValue {
private String devName;
private String devIp;
@XmlJavaTypeAdapter(OtherValuesAdapter.class)
public HashMap <String, String> otherValues;
public String getDevIp() {
return devIp;
}
public void setDevIp(String devIp) {
this.devIp = devIp;
}
public String getDevName() {
return devName;
}
public void setDevName(String devName) {
this.devName = devName;
}
}
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class MapValue {
private String devName;
private String devIp;
@XmlJavaTypeAdapter(OtherValuesAdapter.class)
public HashMap <String, String> otherValues;
public String getDevIp() {
return devIp;
}
public void setDevIp(String devIp) {
this.devIp = devIp;
}
public String getDevName() {
return devName;
}
public void setDevName(String devName) {
this.devName = devName;
}
}
最后,在SOAP服务的声明中,使用这个结构:(注意是sendAlarmMap方法)
import
java.util.List;
import javax.jws. * ;
import javax.jws.soap. * ;
import javax.jws.soap.SOAPBinding. * ;
import java.util.HashMap;
import java.util.Map;
@WebService
public interface NotifyService {
public int sendAlarm (DeviceValue alarm);
public String sendAlarmString (String stralarm);
public List<DeviceValue> sendAlarmArr (List<DeviceValue> arr);
public int sendAlarmMap (MapValue m);
}
import javax.jws. * ;
import javax.jws.soap. * ;
import javax.jws.soap.SOAPBinding. * ;
import java.util.HashMap;
import java.util.Map;
@WebService
public interface NotifyService {
public int sendAlarm (DeviceValue alarm);
public String sendAlarmString (String stralarm);
public List<DeviceValue> sendAlarmArr (List<DeviceValue> arr);
public int sendAlarmMap (MapValue m);
}
下面,我们来看如何通过JAVA及PERL的方式调用这个服务:
JAVA的方式:
NotifyService s
=
(NotifyService) getBean (
"
notifyClient
"
);
MapValue mv = new MapValue ();
mv.otherValues = new HashMap < String, String > ();
mv.otherValues.put ( " hehe2 " , " a " );
mv.otherValues.put ( " 2 " , " b " );
mv.setDevIp ( " he " );
mv.setDevName ( " hehe2 " );
int r = s.sendAlarmMap(mv);
logger.info( " recv: " + r);
MapValue mv = new MapValue ();
mv.otherValues = new HashMap < String, String > ();
mv.otherValues.put ( " hehe2 " , " a " );
mv.otherValues.put ( " 2 " , " b " );
mv.setDevIp ( " he " );
mv.setDevName ( " hehe2 " );
int r = s.sendAlarmMap(mv);
logger.info( " recv: " + r);
PERL的方式:
{
#
call send map alarm
my @params = (SOAP :: Data -> name(arg0 => {
devName => " hehe " ,
devIp => " ip1 " ,
otherValues => [{
item => [
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe2 " , value => " ip2 " }]
}]
}));
my $method = SOAP :: Data -> name( ' sendAlarmMap ' );
my $result = $soap -> call( $method => @params );
print " \nsend map alarm result:\n " ;
if ( $result -> fault)
{
print $result -> faultstring;
}
else
{
print $result -> result;
}
print " \n\n " ;
}
my @params = (SOAP :: Data -> name(arg0 => {
devName => " hehe " ,
devIp => " ip1 " ,
otherValues => [{
item => [
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe1 " , value => " ip1 " } ,
{key => " hehe2 " , value => " ip2 " }]
}]
}));
my $method = SOAP :: Data -> name( ' sendAlarmMap ' );
my $result = $soap -> call( $method => @params );
print " \nsend map alarm result:\n " ;
if ( $result -> fault)
{
print $result -> faultstring;
}
else
{
print $result -> result;
}
print " \n\n " ;
}
产生的SOAP消息如下:
请求:
<? xml version="1.0" encoding="UTF-8" ?> < soap:Envelope xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc ="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd ="http://www.w3.org/2001/XMLSchema" soap:encodingStyle ="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap ="http://schemas.xmlsoap.org/soap/envelope/" >< soap:Body >< sendAlarmMap >< arg0 >< devName > hehe </ devName >< otherValues >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip2 </ value >< key > hehe2 </ key ></ item ></ otherValues >< devIp > ip1 </ devIp ></ arg0 ></ sendAlarmMap ></ soap:Body ></ soap:Envelope >
回应:
< soap:Envelope xmlns:soap ="http://schemas.xmlsoap.org/soap/envelope/" >< soap:Body >< ns1:sendAlarmMapResponse xmlns:ns1 ="http://magic.nms.exchangebit.com/" >< return > 99 </ return ></ ns1:sendAlarmMapResponse ></ soap:Body ></ soap:Envelope >
<? xml version="1.0" encoding="UTF-8" ?> < soap:Envelope xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xmlns:soapenc ="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd ="http://www.w3.org/2001/XMLSchema" soap:encodingStyle ="http://schemas.xmlsoap.org/soap/encoding/" xmlns:soap ="http://schemas.xmlsoap.org/soap/envelope/" >< soap:Body >< sendAlarmMap >< arg0 >< devName > hehe </ devName >< otherValues >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip1 </ value >< key > hehe1 </ key ></ item >< item >< value > ip2 </ value >< key > hehe2 </ key ></ item ></ otherValues >< devIp > ip1 </ devIp ></ arg0 ></ sendAlarmMap ></ soap:Body ></ soap:Envelope >
回应:
< soap:Envelope xmlns:soap ="http://schemas.xmlsoap.org/soap/envelope/" >< soap:Body >< ns1:sendAlarmMapResponse xmlns:ns1 ="http://magic.nms.exchangebit.com/" >< return > 99 </ return ></ ns1:sendAlarmMapResponse ></ soap:Body ></ soap:Envelope >
总结:
有了转换器这个工具,我们可以在SOAP的JAXB绑定里支持各种JAVA的COLLECTION类型,以及自定义类型,打破了SOAP原始支持类型的限制。
有兴趣可以访问下我的生活博客: qqmovie.qzone.com