出處:http://www.ibm.com/developerworks/cn/webservices/ws-jxmap/
本文將討論JAX-RPC1.1中JAVA編程語言的數據類型與XML Schema數據類型之間的映射,并且提供具體的映射實例。<!----><!----> <!---->
本文是J2EE Web服務開發系列文章的第十篇,本文將討論JAX-RPC1.1中JAVA編程語言的數據類型與XML Schema數據類型之間的映射,并且提供具體的映射實例。通過學習本文,讀者能夠理解JAX-RPC中Java到XML之間的映射關系,并且能夠在開發 中合理處理不同的數據類型。
閱讀本文前您需要以下的知識和工具:
- J2EE1.4 SDK,并且會初步使用;
- 掌握基本的JAX-RPC Web服務開發技能;
- 一般的Java編程知識。
本文的參考資料見 參考資料 。
本文的全部代碼在 這里 下載。
?
由 于Web服務調用是通過XML進行數據交換的遠程方法調用,它不像本地調用可以通過引用傳遞參數,JAX-RPC目前的版本只支持按值傳遞參數。也就是 說,當要通過遠程方法調用Web服務時,把參數的一個拷貝傳遞過去。默認情況下,非靜態的和非transient的變量才會拷貝。當從Web服務端返回調 用結果時,又產生一個新的對象。
鑒于Web服務以上的調用機制,所以在參數傳遞時有一定的限制,它只支持以下的數據類型:
- 原始類型(任何Java支持的數據類型,如int);
- 標準java類(String等);
- 由支持的Java類型組成的數組(Array);
- 異常類;
- JAX-RPC值類型。
注意:只有JAX-RPC支持的數據類型才能在Web服務中作為參數傳遞和返回。
我們知道,SOAP、WSDL是和編程語言無關的Web服務協議,故SOAP、WSDL并不定義XML和編程語言之間的映射。JAX-RPC1.1規范定義了以下JAVA到XML之間的映射關系:
- 簡單的內置(built-in)類型的映射(如:xsd:string--java.lang.String);
- 數組(Array,如int[] ,String[][]等),映射到 Java array;
- 簡單的內置(built-in)類型的枚舉(Enumeration), 映射到 Java Enumeration;
- XML Struct 和復雜類型,映射到JavaBean,這個Bean有相關的 getter 和 setter方法。
下面詳細討論這些數據類型的映射。
?
|
|
|
?
下表是Java原始數據類型和XML數據類型之間的映射
表1 原始數據類型與XML 數據類型之間的映射
| Java原始數據類型 | XML 數據類型 |
| boolean | xsd:boolean |
| byte | xsd:byte |
| short | xsd:short |
| int | xsd:int |
| long | xsd:long |
| float | xsd:float |
| double | xsd:double |
注意:這里的原始數據類型中沒有char類型。
我們知道,在Java語言中,每個原始數據類型都有一個對應的Object類,如int和Integer對應,但事實上如果它們表示同一個整數時對于XML來說是一樣的,所以XML把它們統一對待,如:
例程1 Integer的表示方法
<xsd:element name="code" type="xsd:int" nillable="true"/>
<!-- Schema instance -->
<code xsi:nil="true"></code>
|
?
這樣,我們可以在Web服務編程中按照以下的方式來使用原始數據類型:
例程2 原始數據類型的使用
…//Web服務端點接口中的代碼。
public int echoint(int original)throws java.rmi.RemoteException;
…//Web服務實現類中的代碼。
public int echoint(int original){ return original; }
…//Web服務客戶端代碼。
System.out.print("echoint:");
System.out.println(demo.echoint(100));
|
|
|
|
?
標準Java類和XML 數據類型之間的映射關系如表2所示。
表2 標準Java類和XML 數據類型之間的映射
| Java Class | XML 數據類型 |
| 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對應。
這樣,我們可以在Web服務編程中按照以下的方式來使用這些標準Java類型:
例程3 Java標準類的使用
…//Web服務端點接口中的代碼。
public String echoString(String original)throws java.rmi.RemoteException;
…//Web服務實現類中的代碼。
public String echoString(String original){ return original; }
…//Web服務客戶端代碼。
System.out.print("echoString:");
System.out.println(demo.echoString("Hello"));
|
?
可以看出,和原始數據類型一樣,我們并不需要關心JAX-RPC客戶端和服務端怎么進行類型轉換,而是由JAX-RPC運行環境進行自動轉換。
?
|
|
|
?
JAX-RPC支持由JAX-RPC支持的數據類型組成的數組。比如int[],String[]等。多維數組同樣可以被支持,比如:int[][],String[][]。
另外,byte[] 和 Byte[] 都映射為xsd:base64Binary 類型。
例如,可以按照以下方式來使用數組:
例程4 數組的使用
…//Web服務端點接口中的代碼。
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服務實現類中的代碼。
public String[][] echoString2s(String[][] original){ return original; }
…//Web服務客戶端代碼。
///////////原始類型的數組///////////
byte[] ret=demo.echobytes(new byte[]{1,1});
for(int i=0;i<ret.length;i++)
{
System.out.println(ret[i]);
}
///////////基本類型的數組///////////
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]);
}
|
?
注意,上面的代碼中包含了一維的數組,也包含了二維的數組。數組中的數據類型也各不相同。我們看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定義的標準數據類型。在上面映射關系中,Java中String[]映射成Schema一個復雜數據類型:ArrayOfstring。而 String[][]以String[]為基礎進一步定義,它的arrayType是tns:ArrayOfstring[]。
?
|
|
|
?
JAX-RPC規定Web服務拋出的一樣類必須直接或者間接從java.lang.Exception類繼承,這個異常必須是可檢查的異常(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端點接口和實現類中按以下方式來使用這個異常:
例程7 使用異常
…//Web服務端點接口中的代碼。
public MyPoint echoMyPoint(MyPoint original)
throws java.rmi.RemoteException,InvalidPointException;
…//Web服務實現類中的代碼。
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();
}
|
?
這樣,當在服務端實現類出現異常時,將通過SOAP消息把異常類發送到客戶端。我們看這個異常類怎么和XML數據類型映射。
例程8 異常和XML數據類型映射
<complexType name="InvalidPointException">
<sequence>
<element name="message" type="string" nillable="true" />
</sequence>
</complexType>
|
?
可以看出,異常類實際上通過string類型來發送的,其實發送的string就是異常的錯誤堆棧,在客戶端獲得XML形式的錯誤堆棧后,由可以通過這個錯誤堆棧重新構造一個新的異常類,它和服務端拋出的異常類是等價的。
?
|
|
|
?
JAX-RPC值類型是能夠在客戶端和服務端點之間傳遞的Java類,它被映射為xsd:complexType。JAX-RPC值類型必須遵守以下規則:
- Java類必須提供默認的構造方法;
- Java類必須不(直接或者間接)實現java.rmi.Remote接口;
- 可以實現任何Java接口(除java.rmi.Remote接口外)或者擴展自其它類;
- 它可以包含公共的、私有的、受保護的字段,并且公共的字段必須是JAX-RPC支持的數據類型;
- Java類可以包含靜態或者transient字段;
- Java類可以包含一些方法;
- Java類可能被設計成JavaBean。在這種情況下,JavaBean必須依照JavaBeans組件規則,為它的屬性提供getter和setter方法;并且JavaBean的屬性必須是JAX-RPC支持的數據類型。
例如,可以定義一個如下的值類型:
例程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的構造方法必須是默認的:public MyPoint(){}。我們為這個值類型提供了對應的getter和setter方法,它可以說是一個JavaBean。
其它的值類型可以從這個值類型擴展,如例程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();
}
}
|
?
實際上,對于上面的值類型,XML仍然作為復雜數據類型來處理的,我們來看它的定義:
例程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值類型的擴展(extend)對應于XML Schema中定義的擴展(extension)。
?
|
|
|
?
JAX- RPC規范規定了XML數據類型和Java類型之間的標準的映射,這些映射支持SOAP1.1編碼和XML Schema規則。除了這些標準的映射之外,JAX-RPC也提供了一些擴展映射的API,這些API在javax.xml.rpc.encoding 包中定義,通過這些API,可以開發出可插入的序列化和反序列化器。
注意: XML/SOAP序列化語義代與標準的Java序列化不同。標準的序列化狀態包含public、private、protected以及包級的非 transient字段。RMI-IIOP使用標準的序列化語義來序列化值類型。而XML/SOAP序列化通常把值類型表示成對應的XML形式。
序列化類型擴展的實現是和具體的廠商相關的,所以在這里不準備詳細討論。在J2EESDK1.4中,支持以下類型的序列化:
- List(ArrayList、LinkedList、Stack、Vector);
- Map(HashMap、HashTable、Properties、TreeMap);
- Set(HashSet、TreeSet)。
注意:J2EESDK1.4實現不支持Collection類的序列化。
這樣,我們可以在編程中按照以下的方式來使用Java集合類型:
例程12 使用擴展類型映射
…//Web服務端點接口中的代碼。
/**
*集合類
*/
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服務實現類中的代碼。
public Map echoMap(Map original){ return original; }
public List echoList(List original){ return original; }
public Set echoSet(Set original){ return original; }
|
?
我們可以看到在生成的WSDL文件中,JAX-RPC參考實現工具進行了以下方式的映射:
例程13 擴展類型映射
<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參考實現相關的。List和Set都以collection為基礎定義,而collection則以XML 的Array為基礎定義的。而Map的定義基于mapEntry,mapEntry就是包含了key和value元素的復雜XML數據類型。
需要注意的是,List、Map或者Set集合對象中包含的數據類型必須是JAX-RPC支持的數據類型,否則序列化將失敗。
?
|
|
|
?
本文后面附帶了上面例子中的代碼。首先在J2EE1.4SDK下部署這個應用(java-xml.ear),然后轉到src目錄,通過執行:
ant run-client
來運行客戶端程序。
運行的效果如圖1所示。
|
|
|
?
通 過上面的介紹,我們應該能夠理解JAX-RPC數據類型和XML數據類型之間的映射關系,并且能夠適當使用JAX-RPC數據類型。需要注意的是,只有 JAX-RPC支持的數據類型才能在Web服務中作為參數傳遞和返回。JAX-RPC除了提供了標準的映射外,還提供了擴展的數據類型映射框架,通過這個 框架,不同的廠商或者開發者可以根據自己的需要開發自定義的序列化和反序列化器,從而實現復雜數據類型的映射。比如開發者為了提高系統性能,開發出基于 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規范, http://java.sun.com/xml/downloads/jaxrpc.html 。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061
微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元

