出處:http://www.ibm.com/developerworks/cn/webservices/ws-jxmap/
本文將討論JAX-RPC1.1中JAVA編程語(yǔ)言的數(shù)據(jù)類型與XML Schema數(shù)據(jù)類型之間的映射,并且提供具體的映射實(shí)例。<!----><!----> <!---->
本文是J2EE Web服務(wù)開發(fā)系列文章的第十篇,本文將討論JAX-RPC1.1中JAVA編程語(yǔ)言的數(shù)據(jù)類型與XML Schema數(shù)據(jù)類型之間的映射,并且提供具體的映射實(shí)例。通過(guò)學(xué)習(xí)本文,讀者能夠理解JAX-RPC中Java到XML之間的映射關(guān)系,并且能夠在開發(fā) 中合理處理不同的數(shù)據(jù)類型。
閱讀本文前您需要以下的知識(shí)和工具:
- J2EE1.4 SDK,并且會(huì)初步使用;
- 掌握基本的JAX-RPC Web服務(wù)開發(fā)技能;
- 一般的Java編程知識(shí)。
本文的參考資料見 參考資料 。
本文的全部代碼在 這里 下載。
?
由 于Web服務(wù)調(diào)用是通過(guò)XML進(jìn)行數(shù)據(jù)交換的遠(yuǎn)程方法調(diào)用,它不像本地調(diào)用可以通過(guò)引用傳遞參數(shù),JAX-RPC目前的版本只支持按值傳遞參數(shù)。也就是 說(shuō),當(dāng)要通過(guò)遠(yuǎn)程方法調(diào)用Web服務(wù)時(shí),把參數(shù)的一個(gè)拷貝傳遞過(guò)去。默認(rèn)情況下,非靜態(tài)的和非transient的變量才會(huì)拷貝。當(dāng)從Web服務(wù)端返回調(diào) 用結(jié)果時(shí),又產(chǎn)生一個(gè)新的對(duì)象。
鑒于Web服務(wù)以上的調(diào)用機(jī)制,所以在參數(shù)傳遞時(shí)有一定的限制,它只支持以下的數(shù)據(jù)類型:
- 原始類型(任何Java支持的數(shù)據(jù)類型,如int);
- 標(biāo)準(zhǔn)java類(String等);
- 由支持的Java類型組成的數(shù)組(Array);
- 異常類;
- JAX-RPC值類型。
注意:只有JAX-RPC支持的數(shù)據(jù)類型才能在Web服務(wù)中作為參數(shù)傳遞和返回。
我們知道,SOAP、WSDL是和編程語(yǔ)言無(wú)關(guān)的Web服務(wù)協(xié)議,故SOAP、WSDL并不定義XML和編程語(yǔ)言之間的映射。JAX-RPC1.1規(guī)范定義了以下JAVA到XML之間的映射關(guān)系:
- 簡(jiǎn)單的內(nèi)置(built-in)類型的映射(如:xsd:string--java.lang.String);
- 數(shù)組(Array,如int[] ,String[][]等),映射到 Java array;
- 簡(jiǎn)單的內(nèi)置(built-in)類型的枚舉(Enumeration), 映射到 Java Enumeration;
- XML Struct 和復(fù)雜類型,映射到JavaBean,這個(gè)Bean有相關(guān)的 getter 和 setter方法。
下面詳細(xì)討論這些數(shù)據(jù)類型的映射。
?
![]() ![]() |
![]()
|
?
下表是Java原始數(shù)據(jù)類型和XML數(shù)據(jù)類型之間的映射
表1 原始數(shù)據(jù)類型與XML 數(shù)據(jù)類型之間的映射
Java原始數(shù)據(jù)類型 | XML 數(shù)據(jù)類型 |
boolean | xsd:boolean |
byte | xsd:byte |
short | xsd:short |
int | xsd:int |
long | xsd:long |
float | xsd:float |
double | xsd:double |
注意:這里的原始數(shù)據(jù)類型中沒有char類型。
我們知道,在Java語(yǔ)言中,每個(gè)原始數(shù)據(jù)類型都有一個(gè)對(duì)應(yīng)的Object類,如int和Integer對(duì)應(yīng),但事實(shí)上如果它們表示同一個(gè)整數(shù)時(shí)對(duì)于XML來(lái)說(shuō)是一樣的,所以XML把它們統(tǒng)一對(duì)待,如:
例程1 Integer的表示方法
<xsd:element name="code" type="xsd:int" nillable="true"/> <!-- Schema instance --> <code xsi:nil="true"></code> |
?
這樣,我們可以在Web服務(wù)編程中按照以下的方式來(lái)使用原始數(shù)據(jù)類型:
例程2 原始數(shù)據(jù)類型的使用
…//Web服務(wù)端點(diǎn)接口中的代碼。 public int echoint(int original)throws java.rmi.RemoteException; …//Web服務(wù)實(shí)現(xiàn)類中的代碼。 public int echoint(int original){ return original; } …//Web服務(wù)客戶端代碼。 System.out.print("echoint:"); System.out.println(demo.echoint(100)); |
![]() ![]() |
![]()
|
?
標(biāo)準(zhǔn)Java類和XML 數(shù)據(jù)類型之間的映射關(guān)系如表2所示。
表2 標(biāo)準(zhǔn)Java類和XML 數(shù)據(jù)類型之間的映射
Java Class | XML 數(shù)據(jù)類型 |
java.lang.String | xsd:string |
java.math.BigInteger | xsd:integer |
java.math.BigDecimal | xsd:decimal |
java.util.Calendar | xsd:dateTime |
java.util.Date | xsd:dateTime |
javax.xml.namespace.QName | xsd:QName |
java.net.URI | xsd:anyURI |
java.util.Calendar和java.util.Date都與XML的xsd:dateTime對(duì)應(yīng)。
這樣,我們可以在Web服務(wù)編程中按照以下的方式來(lái)使用這些標(biāo)準(zhǔn)Java類型:
例程3 Java標(biāo)準(zhǔn)類的使用
…//Web服務(wù)端點(diǎn)接口中的代碼。 public String echoString(String original)throws java.rmi.RemoteException; …//Web服務(wù)實(shí)現(xiàn)類中的代碼。 public String echoString(String original){ return original; } …//Web服務(wù)客戶端代碼。 System.out.print("echoString:"); System.out.println(demo.echoString("Hello")); |
?
可以看出,和原始數(shù)據(jù)類型一樣,我們并不需要關(guān)心JAX-RPC客戶端和服務(wù)端怎么進(jìn)行類型轉(zhuǎn)換,而是由JAX-RPC運(yùn)行環(huán)境進(jìn)行自動(dòng)轉(zhuǎn)換。
?
![]() ![]() |
![]()
|
?
JAX-RPC支持由JAX-RPC支持的數(shù)據(jù)類型組成的數(shù)組。比如int[],String[]等。多維數(shù)組同樣可以被支持,比如:int[][],String[][]。
另外,byte[] 和 Byte[] 都映射為xsd:base64Binary 類型。
例如,可以按照以下方式來(lái)使用數(shù)組:
例程4 數(shù)組的使用
…//Web服務(wù)端點(diǎn)接口中的代碼。 public int[] echoints(int[] original)throws java.rmi.RemoteException; public String[] echoStrings(String[] original)throws java.rmi.RemoteException; public String[][] echoString2s(String[][] original)throws java.rmi.RemoteException; public MyPoint[] echoMyPoints(MyPoint[] original) throws java.rmi.RemoteException,InvalidPointException; …//Web服務(wù)實(shí)現(xiàn)類中的代碼。 public String[][] echoString2s(String[][] original){ return original; } …//Web服務(wù)客戶端代碼。 ///////////原始類型的數(shù)組/////////// byte[] ret=demo.echobytes(new byte[]{1,1}); for(int i=0;i<ret.length;i++) { System.out.println(ret[i]); } ///////////基本類型的數(shù)組/////////// System.out.print("echoString[]:"); String[] strings=new String[]{"test1","test2"}; String[] ret_strings=demo.echoStrings(strings); for(int i=0;i<ret_strings.length;i++) { System.out.println(ret_strings[i]); } |
?
注意,上面的代碼中包含了一維的數(shù)組,也包含了二維的數(shù)組。數(shù)組中的數(shù)據(jù)類型也各不相同。我們看String[]和String[][]怎么在WSDL中描述的:
例程5 String[]和String[][]到XML的映射
<!--String[][]到XML之間的映射--> <complexType name=" ArrayOfArrayOfstring"> <complexContent> <restriction base="soap11enc:Array"> <attribute ref="soap11enc:arrayType" wsdl:arrayType=" tns:ArrayOfstring[]" /> </restriction> </complexContent> </complexType> <!--String[]到XML之間的映射--> <complexType name=" ArrayOfstring"> <complexContent> <restriction base="soap11enc:Array"> <attribute ref="soap11enc:arrayType" wsdl:arrayType=" string[]" /> </restriction> </complexContent> </complexType> |
?
string[] 是XML Schema定義的標(biāo)準(zhǔn)數(shù)據(jù)類型。在上面映射關(guān)系中,Java中String[]映射成Schema一個(gè)復(fù)雜數(shù)據(jù)類型:ArrayOfstring。而 String[][]以String[]為基礎(chǔ)進(jìn)一步定義,它的arrayType是tns:ArrayOfstring[]。
?
![]() ![]() |
![]()
|
?
JAX-RPC規(guī)定Web服務(wù)拋出的一樣類必須直接或者間接從java.lang.Exception類繼承,這個(gè)異常必須是可檢查的異常(checked Exception),必須不能直接或者間接繼承自java.lang. RuntimeException類。
如我們可以定義如下的異常類:
例程6 定義JAX-RPC異常類
package com.hellking.study.webservice.datatype; /** *jax-rpc異常類。 */ public class InvalidPointException extends java.lang.Exception { public InvalidPointException(String msg) { super(msg); } public String toString() { return "InvalidPointException"+getMessage(); } } |
?
可以在JAX-RPC端點(diǎn)接口和實(shí)現(xiàn)類中按以下方式來(lái)使用這個(gè)異常:
例程7 使用異常
…//Web服務(wù)端點(diǎn)接口中的代碼。 public MyPoint echoMyPoint(MyPoint original) throws java.rmi.RemoteException,InvalidPointException; …//Web服務(wù)實(shí)現(xiàn)類中的代碼。 public MyPoint echoMyPoint(MyPoint original) throws InvalidPointException{ return original; } …//在客戶端使用異常 try { MyPoint ret_mp=demo.echoMyPoint(mp); System.out.println(ret_mp.toString()); } catch(InvalidPointException e) { e.printStackTrace(); } |
?
這樣,當(dāng)在服務(wù)端實(shí)現(xiàn)類出現(xiàn)異常時(shí),將通過(guò)SOAP消息把異常類發(fā)送到客戶端。我們看這個(gè)異常類怎么和XML數(shù)據(jù)類型映射。
例程8 異常和XML數(shù)據(jù)類型映射
<complexType name="InvalidPointException"> <sequence> <element name="message" type="string" nillable="true" /> </sequence> </complexType> |
?
可以看出,異常類實(shí)際上通過(guò)string類型來(lái)發(fā)送的,其實(shí)發(fā)送的string就是異常的錯(cuò)誤堆棧,在客戶端獲得XML形式的錯(cuò)誤堆棧后,由可以通過(guò)這個(gè)錯(cuò)誤堆棧重新構(gòu)造一個(gè)新的異常類,它和服務(wù)端拋出的異常類是等價(jià)的。
?
![]() ![]() |
![]()
|
?
JAX-RPC值類型是能夠在客戶端和服務(wù)端點(diǎn)之間傳遞的Java類,它被映射為xsd:complexType。JAX-RPC值類型必須遵守以下規(guī)則:
- Java類必須提供默認(rèn)的構(gòu)造方法;
- Java類必須不(直接或者間接)實(shí)現(xiàn)java.rmi.Remote接口;
- 可以實(shí)現(xiàn)任何Java接口(除java.rmi.Remote接口外)或者擴(kuò)展自其它類;
- 它可以包含公共的、私有的、受保護(hù)的字段,并且公共的字段必須是JAX-RPC支持的數(shù)據(jù)類型;
- Java類可以包含靜態(tài)或者transient字段;
- Java類可以包含一些方法;
- Java類可能被設(shè)計(jì)成JavaBean。在這種情況下,JavaBean必須依照J(rèn)avaBeans組件規(guī)則,為它的屬性提供getter和setter方法;并且JavaBean的屬性必須是JAX-RPC支持的數(shù)據(jù)類型。
例如,可以定義一個(gè)如下的值類型:
例程9 JAX-RPC的值類型
package com.hellking.study.webservice.datatype; /** *jax-rpc值類型:Value Type */ public class MyPoint { int x; int y; public MyPoint(){} public int getX(){return x;} public int getY(){return y;} public void setY(int y){this.y=y;} public void setX(int x){this.x=x;} public String toString() { return new StringBuffer().append("X:").append(x).append("Y:").append(y).toString(); } } |
?
注意,MyPoint的構(gòu)造方法必須是默認(rèn)的:public MyPoint(){}。我們?yōu)檫@個(gè)值類型提供了對(duì)應(yīng)的getter和setter方法,它可以說(shuō)是一個(gè)JavaBean。
其它的值類型可以從這個(gè)值類型擴(kuò)展,如例程10所示。
例程10 值類型的繼承
package com.hellking.study.webservice.datatype; /** *jax-rpc值類型:Value Type */ public class ExtendPoint extends MyPoint { int z; public ExtendPoint(){} public int getZ(){return z;} public void setZ(int z){this.z=z;} public String toString() { return new StringBuffer(super.toString()).append("Z:").append(z).toString(); } } |
?
實(shí)際上,對(duì)于上面的值類型,XML仍然作為復(fù)雜數(shù)據(jù)類型來(lái)處理的,我們來(lái)看它的定義:
例程11 值類型和XML之間的映射
<complexType name=" ExtendPoint"> <complexContent> <extension base="tns:MyPoint"> <sequence> <element name="z" type="int" /> </sequence> </extension> </complexContent> </complexType> <complexType name=" MyPoint"> <sequence> <element name="x" type="int" /> <element name="y" type="int" /> </sequence> </complexType> |
?
可以看到,Java值類型的擴(kuò)展(extend)對(duì)應(yīng)于XML Schema中定義的擴(kuò)展(extension)。
?
![]() ![]() |
![]()
|
?
JAX- RPC規(guī)范規(guī)定了XML數(shù)據(jù)類型和Java類型之間的標(biāo)準(zhǔn)的映射,這些映射支持SOAP1.1編碼和XML Schema規(guī)則。除了這些標(biāo)準(zhǔn)的映射之外,JAX-RPC也提供了一些擴(kuò)展映射的API,這些API在javax.xml.rpc.encoding 包中定義,通過(guò)這些API,可以開發(fā)出可插入的序列化和反序列化器。
注意: XML/SOAP序列化語(yǔ)義代與標(biāo)準(zhǔn)的Java序列化不同。標(biāo)準(zhǔn)的序列化狀態(tài)包含public、private、protected以及包級(jí)的非 transient字段。RMI-IIOP使用標(biāo)準(zhǔn)的序列化語(yǔ)義來(lái)序列化值類型。而XML/SOAP序列化通常把值類型表示成對(duì)應(yīng)的XML形式。
序列化類型擴(kuò)展的實(shí)現(xiàn)是和具體的廠商相關(guān)的,所以在這里不準(zhǔn)備詳細(xì)討論。在J2EESDK1.4中,支持以下類型的序列化:
- List(ArrayList、LinkedList、Stack、Vector);
- Map(HashMap、HashTable、Properties、TreeMap);
- Set(HashSet、TreeSet)。
注意:J2EESDK1.4實(shí)現(xiàn)不支持Collection類的序列化。
這樣,我們可以在編程中按照以下的方式來(lái)使用Java集合類型:
例程12 使用擴(kuò)展類型映射
…//Web服務(wù)端點(diǎn)接口中的代碼。 /** *集合類 */ public Map echoMap(Map original)throws java.rmi.RemoteException; public List echoList(List original)throws java.rmi.RemoteException; public Set echoSet(Set original)throws java.rmi.RemoteException; …//Web服務(wù)實(shí)現(xiàn)類中的代碼。 public Map echoMap(Map original){ return original; } public List echoList(List original){ return original; } public Set echoSet(Set original){ return original; } |
?
我們可以看到在生成的WSDL文件中,JAX-RPC參考實(shí)現(xiàn)工具進(jìn)行了以下方式的映射:
例程13 擴(kuò)展類型映射
<schema targetNamespace="http://java.sun.com/jax-rpc-ri/internal" xmlns:tns="http://java.sun.com/jax-rpc-ri/internal" xmlns:soap11-enc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns="http://www.w3.org/2001/XMLSchema"> <import namespace="http://schemas.xmlsoap.org/soap/encoding/" /> <import namespace="urn:dataType" /> <complexType name=" list"> <complexContent> <extension base="tns: collection"> <sequence /> </extension> </complexContent> </complexType> <complexType name=" collection"> <complexContent> <restriction base="soap11-enc:Array"> <attribute ref="soap11-enc:arrayType" wsdl:arrayType="anyType[]" /> </restriction> </complexContent> </complexType> <complexType name=" map"> <complexContent> <restriction base="soap11-enc:Array"> <attribute ref="soap11-enc:arrayType" wsdl:arrayType="tns:mapEntry[]" /> </restriction> </complexContent> </complexType> <complexType name=" mapEntry"> <sequence> <element name="key" type="anyType" /> <element name="value" type="anyType" /> </sequence> </complexType> <complexType name=" set"> <complexContent> <extension base="tns: collection"> <sequence /> </extension> </complexContent> </complexType> </schema> |
?
首 先,從名稱空間targetNamespace="http://java.sun.com/jax-rpc-ri/internal"可以看出上面的映 射是和JAX-RPC參考實(shí)現(xiàn)相關(guān)的。List和Set都以collection為基礎(chǔ)定義,而collection則以XML 的Array為基礎(chǔ)定義的。而Map的定義基于mapEntry,mapEntry就是包含了key和value元素的復(fù)雜XML數(shù)據(jù)類型。
需要注意的是,List、Map或者Set集合對(duì)象中包含的數(shù)據(jù)類型必須是JAX-RPC支持的數(shù)據(jù)類型,否則序列化將失敗。
?
![]() ![]() |
![]()
|
?
本文后面附帶了上面例子中的代碼。首先在J2EE1.4SDK下部署這個(gè)應(yīng)用(java-xml.ear),然后轉(zhuǎn)到src目錄,通過(guò)執(zhí)行:
ant run-client
來(lái)運(yùn)行客戶端程序。
運(yùn)行的效果如圖1所示。
![]() ![]() |
![]()
|
?
通 過(guò)上面的介紹,我們應(yīng)該能夠理解JAX-RPC數(shù)據(jù)類型和XML數(shù)據(jù)類型之間的映射關(guān)系,并且能夠適當(dāng)使用JAX-RPC數(shù)據(jù)類型。需要注意的是,只有 JAX-RPC支持的數(shù)據(jù)類型才能在Web服務(wù)中作為參數(shù)傳遞和返回。JAX-RPC除了提供了標(biāo)準(zhǔn)的映射外,還提供了擴(kuò)展的數(shù)據(jù)類型映射框架,通過(guò)這個(gè) 框架,不同的廠商或者開發(fā)者可以根據(jù)自己的需要開發(fā)自定義的序列化和反序列化器,從而實(shí)現(xiàn)復(fù)雜數(shù)據(jù)類型的映射。比如開發(fā)者為了提高系統(tǒng)性能,開發(fā)出基于 SAX的序列化器。
本文的全部代碼在 這里 下載。
下載J2EESDK1.4 http://java.sun.com/downloads/ 。
J2EE Home Page, java.sun.com/j2ee 。
J2EE 1.4 (JSR 151), www.jcp.org/jsr/detail/151.jsp 。
Web Services for J2EE (JSR 109), www.jcp.org/jsr/detail/109.jsp 。
JAXM API http://java.sun.com/webservices 。
Jwdp1.3 http://java.sun.com/webservices 。
JAX-RPC規(guī)范, http://java.sun.com/xml/downloads/jaxrpc.html 。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫作最大的動(dòng)力,如果您喜歡我的文章,感覺我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
