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;
}
再定义一个转换类:(数组到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;
}
}
我们需要在一个结构中来包含使用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;
} 
}
最后,在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);
}
下面,我们来看如何通过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);
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
"
;
}
产生的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
>
总结:
有了转换器这个工具,我们可以在SOAP的JAXB绑定里支持各种JAVA的COLLECTION类型,以及自定义类型,打破了SOAP原始支持类型的限制。
本文介绍如何在CXF框架中使用JAXB数据绑定支持HashMap类型,通过自定义适配器实现数组到HashMap的转换,并展示了Java及Perl两种语言的调用示例。
584

被折叠的 条评论
为什么被折叠?



