目錄
項(xiàng)目簡(jiǎn)介... 4
典型的應(yīng)用場(chǎng)合... 5
系統(tǒng)架構(gòu)分析... 5
實(shí)例講解... 6
創(chuàng)建需要序列化的對(duì)象類... 6
初始化XStream類... 9
注冊(cè)需要轉(zhuǎn)換的類的別名... 10
將對(duì)象序列化為XML文檔... 10
從XML文件反序列化成對(duì)象... 11
結(jié)束語... 11
參考資料... 11
開源項(xiàng)目XStream是一套簡(jiǎn)單實(shí)用的類庫,用于序列化對(duì)象與XML對(duì)象之間的相互轉(zhuǎn)換。本文以XStream 1.1.2版進(jìn)行說明,它具有以下幾個(gè)特點(diǎn):
? 靈活易用:在更高的層次上提供了簡(jiǎn)單、靈活、易用的統(tǒng)一接口,用戶無需了解項(xiàng)目的底層細(xì)節(jié)
? 無需映射:大多數(shù)對(duì)象都可以在無需映射的情況下進(jìn)行序列化與反序列化的操作
? 高速穩(wěn)定:設(shè)計(jì)時(shí)力求達(dá)到的最重要的指標(biāo)是解析速度快、占用內(nèi)存少,以使之能夠適用于大的對(duì)象處理或是對(duì)信息吞吐量要求高的系統(tǒng)
? 清晰易懂:項(xiàng)目采用reflection機(jī)制得到無冗余信息的XML文件。所生成的XML文件較本地Java序列化產(chǎn)物更簡(jiǎn)潔,格式更清晰,更便于用戶閱讀
? 無需修改:完全序列化包括private和final類型在內(nèi)的全部內(nèi)部字段。支持非公有類和內(nèi)部類,類可以沒有缺省的構(gòu)造函數(shù)
? 易于集成:通過實(shí)現(xiàn)特定的接口,XStream可以直接與其它任何樹型結(jié)構(gòu)進(jìn)行序列化與反序列化操作(而不僅僅是XML格式)
? 靈活轉(zhuǎn)換:轉(zhuǎn)換策略是可以定制的,允許用戶自定義特殊類型的對(duì)象如何以XML格式存儲(chǔ)。
? 錯(cuò)誤處理:由于XML資料不合法而造成異常時(shí),會(huì)提供詳細(xì)地診斷信息幫助處理問題。
XStream主要應(yīng)用于以下場(chǎng)合:
ü 數(shù)據(jù)對(duì)象的持久化
ü 數(shù)據(jù)交換
ü 配置文件
XStream系統(tǒng)架構(gòu)分析
XStream的架構(gòu)主要由四部分組成:
2 Converters(轉(zhuǎn)換器)
當(dāng)XStream遇到需要輪換的對(duì)象時(shí),它會(huì)委派給合適的轉(zhuǎn)換器實(shí)現(xiàn),XStream為通用類型提供了多種轉(zhuǎn)換器實(shí)現(xiàn),包括基本數(shù)據(jù)類型、String、Collections、Arrays、null、Date,等等。
XStream提供了缺省的轉(zhuǎn)換器,當(dāng)需要轉(zhuǎn)換的數(shù)據(jù)對(duì)象沒有匹配的轉(zhuǎn)換器時(shí)會(huì)使用。是通過反射機(jī)制自動(dòng)完成對(duì)對(duì)象內(nèi)所有字段的映射。
2 IO(輸入/輸出)
XStream是通過接口HierarchicalStramWriter和HierarchialStreamReader從底層XML數(shù)據(jù)中抽象而來的,上面的接口分別用于序列化和反序列化操作。
該特性使得XStream可以直接使用XML解析類從數(shù)據(jù)流中讀取數(shù)據(jù),或者是直接從已經(jīng)存在的結(jié)構(gòu)中提取數(shù)據(jù)(比如DOM)。如果XStream所操作的XML數(shù)據(jù)已經(jīng)部分被其它XML解析類處理過了(比如SOAP類的實(shí)例),這樣就可以避免在我們這一層的再次解析操作。
2 Context(上下文引用)
在XStream序列化或反序列化對(duì)象時(shí),它會(huì)創(chuàng)建兩個(gè)類MarshallingContext和UnmarshallingContext,由它們來處理數(shù)據(jù),以及委派合適的轉(zhuǎn)換器。
XStream提供了三對(duì)上下文的缺省實(shí)現(xiàn),它們之間有著細(xì)微的差別。缺省值可以通過方法XStream.setMode()來改變,需要傳遞下面參數(shù)中的一個(gè):
? XStream.XPATH_REFERENCES
(缺省的)通過XPath引用來標(biāo)識(shí)重復(fù)的引用。這樣產(chǎn)生的XML具有最小的混亂性。
? XStream.ID_REFERENCES
使用ID引用來標(biāo)識(shí)重復(fù)的引用。在一些場(chǎng)合,比如使用手寫XML時(shí),這樣將會(huì)更易于操作
? XStream.NO_REFERENCES
這種情況將失去對(duì)圖形對(duì)象的支持,僅把對(duì)象看作為樹型結(jié)構(gòu)。重復(fù)的引用被視作兩個(gè)不同的對(duì)象,循環(huán)引用會(huì)導(dǎo)致異常產(chǎn)生。相對(duì)于上面兩種模式,這種模式速度會(huì)更快,占用內(nèi)存會(huì)更少。
2 Facade(統(tǒng)一入口)
主要類XStream用作所有項(xiàng)目的入口點(diǎn)。它將上面所提及的重要組件集成在一起,提供更簡(jiǎn)單易用的API操作。
下面我們通過一個(gè)簡(jiǎn)單的例子來了解XStream是如何工作的。
/**個(gè)人信息類*/
public class Person
{
/**
* 構(gòu)造函數(shù)
* @param fn 名稱前部分
* @param ln名稱后部分
* @param faxn 傳真號(hào)碼
* @param mobilen 移動(dòng)電話
*/
public Person(String fn, String ln, PhoneNumber faxn, PhoneNumber mobilen)
{
this.firstName = fn;
this.lastName = ln;
this.faxNumber = faxn;
this.mobileNumber = mobilen;
}
/**
* 構(gòu)造函數(shù)
* @param fn 名稱前部分
* @param ln名稱后部分
*/
public Person(String fn, String ln)
{
this.firstName = fn;
this.lastName = ln;
}
private String firstName;
private String lastName;
private PhoneNumber faxNumber;
private PhoneNumber mobileNumber;
/**
* @return Returns the faxNumber.
*/
public PhoneNumber getFaxNumber()
{
return faxNumber;
}
/**
* @param faxNumber
* The faxNumber to set.
*/
public void setFaxNumber(PhoneNumber faxNumber)
{
this.faxNumber = faxNumber;
}
/**
* @return Returns the firstName.
*/
public String getFirstName()
{
return firstName;
}
/**
* @param firstName
* The firstName to set.
*/
public void setFirstName(String firstName)
{
this.firstName = firstName;
}
/**
* @return Returns the lastName.
*/
public String getLastName()
{
return lastName;
}
/**
* @param lastName
* The lastName to set.
*/
public void setLastName(String lastName)
{
this.lastName = lastName;
}
/**
* @return Returns the mobileNumber.
*/
public PhoneNumber getMobileNumber()
{
return mobileNumber;
}
/**
* @param mobileNumber
* The mobileNumber to set.
*/
public void setMobileNumber(PhoneNumber mobileNumber)
{
this.mobileNumber = mobileNumber;
}
}
/**電話號(hào)碼信息類*/
public class PhoneNumber
{
private int phoneId;
private String phoneNumber;
/**
* 構(gòu)造函數(shù)
* @param phoneId ID號(hào)碼
* @param phoneNumber 電話號(hào)碼
*/
public PhoneNumber(int phoneId, String phoneNumber)
{
super();
this.phoneId = phoneId;
this.phoneNumber = phoneNumber;
}
/**
* @return Returns the phoneNumber.
*/
public String getPhoneNumber()
{
return phoneNumber;
}
/**
* @param phoneNumber
* The phoneNumber to set.
*/
public void setPhoneNumber(String phoneNumber)
{
this.phoneNumber = phoneNumber;
}
/**
* @return Returns the phoneId.
*/
public int getPhoneId()
{
return phoneId;
}
/**
* @param phoneId
* The phoneId to set.
*/
public void setPhoneId(int phoneId)
{
this.phoneId = phoneId;
}
}
這里定義的屬性都為private,XStream沒有強(qiáng)制規(guī)定屬性的可見性,默認(rèn)情況下所有屬性都會(huì)進(jìn)行轉(zhuǎn)換;雖然XStream不強(qiáng)制要求你必須要有setter和getter方法,也不要求你要有一個(gè)默認(rèn)的類構(gòu)造方法,但是在實(shí)際應(yīng)用時(shí),這些還是必須的,因?yàn)槟阍诔绦蛑行枰獮閷?duì)象設(shè)置屬性,需要構(gòu)造對(duì)象,如果沒有這些方法程序是不能編譯通過的。
使用以下的語句進(jìn)行初始化操作:
XStream xstream = new XStream();
默認(rèn)情況下,XStream會(huì)采用Xpp3庫,XPP3是一種運(yùn)行效率非常高的XML全解析實(shí)現(xiàn)。如果你不想依靠Xpp3庫的話,也可以使用一個(gè)標(biāo)準(zhǔn)的JAXP DOM解析器,可以采用以下語句進(jìn)行初始化:
//不使用XPP3庫
XStream xstream = new XStream(new DomDriver());
此xstream實(shí)例,為線程安全的,可以供多個(gè)線程進(jìn)行調(diào)用,共享使用。參考com.thoughtworks.xstream.io.xml包,會(huì)發(fā)現(xiàn)系統(tǒng)提供了多種標(biāo)識(shí)解析器供我們選擇,包括,DomDriver、JDomDriver、StaxDriver等等。
現(xiàn)在,為了使XStream輸出的XML文件更簡(jiǎn)練,我們要為需要轉(zhuǎn)換的用戶類設(shè)置別名,這些明會(huì)在轉(zhuǎn)換過程中用于結(jié)點(diǎn)設(shè)置,注冊(cè)別名使用以下的語句:
xstream.alias(“person”, Person.class);
xstream.alias(“phonenumber”, PhoneNumber.class);
當(dāng)然,這一步不是必須的,如果不進(jìn)行注冊(cè)的話,XStream默認(rèn)會(huì)在轉(zhuǎn)換時(shí),將用戶類的全限定名稱加入到XML文件中,如com.test.Person,如果在數(shù)據(jù)量較大的時(shí)候,生成的XML文件會(huì)增大不少。
到了這一步,我們就可以將一個(gè)Java對(duì)象序列化為XML文檔了,先聲明一個(gè)Person對(duì)象,然后為該對(duì)象設(shè)置一個(gè)手機(jī)號(hào)碼,一個(gè)傳真號(hào)碼,使用下面的語句:
//生成Person對(duì)象,并注冊(cè)屬性
Person joe = new Person("Bill", "Gates");
joe.setFaxNumber(new PhoneNumber(101, "83501194"));
joe.setMobileNumber(new PhoneNumber(102, "13686447788"));
下面就是將生成的對(duì)象序列化,我們需要做的只是簡(jiǎn)單的使用下面的一個(gè)語句就可以:
String xmls = xstream.toXML(joe);
從結(jié)果我們可以看出,生成的XML文件非常簡(jiǎn)潔,除了必要的結(jié)點(diǎn)外,沒有一絲多余的信息存在。參考下面的生成結(jié)果:
<person>
<firstName>Bill</firstName>
<lastName>Gates</lastName>
<faxNumber>
<phoneId>101</phoneId>
<phoneNumber>83501194</phoneNumber>
</faxNumber>
<mobileNumber>
<phoneId>102</phoneId>
<phoneNumber>13686447788</phoneNumber>
</mobileNumber>
</person>
從XML文件反序列化成對(duì)象
從一個(gè)XML文件反序列化出一個(gè)對(duì)象同樣簡(jiǎn)單,一起來看下面的代碼:
Person newJoe = (Person)xstream.fromXML(xmls);
通過上面的實(shí)例,我們可以看出,使用XStream來處理對(duì)象的序列化和反序列化很簡(jiǎn)單,只需要幾行代碼即可,而且該項(xiàng)目對(duì)標(biāo)識(shí)的XML解析器有很好的支持,最重要的是生成的XML很“干凈”,沒有過多的冗余信息,該項(xiàng)目還在持續(xù)進(jìn)行中,讓我們一起來關(guān)注它吧!
l XStream官方資料 http://xstream.codehaus.org/index.html
l 本例相關(guān)代碼(附件)