根據 DTD 或模式生成數據類(lèi)
Dennis M. Sosnoski總裁, Sosnoski Software Solutions,Inc.
2003 年 6 月
企業(yè) Java 專(zhuān)家 Dennis Sosnoski 研究了幾種 XML 數據綁定方法,這些方法根據用于 XML 文檔的 W3C XML Schema 或 DTD 文法來(lái)生成代碼。他從人們期待已久的 JAXB 標準(馬上就要由 Java Community Process,JCP 發(fā)布了)入手,然后總結了其它一些目前可用的框架。最后,他討論了如何以及何時(shí)以最佳方式將依據文法的代碼生成應用到應用程序中。
數據綁定 提供了一種簡(jiǎn)單而直接的方法,以在 Java 平臺應用程序中使用 XML。有了數據綁定,應用程序可以在很大程度上忽略 XML 文檔的實(shí)際結構,而直接使用那些文檔的數據內容。雖然這種方法不能適合于所有應用程序,但在一般情況下,對于那些將 XML 用于數據交換的應用程序是比較理想的。
除了簡(jiǎn)化編程之外,數據綁定還提供了其它一些好處。由于數據綁定對許多文檔細節進(jìn)行了抽象,因此對于在內存中處理文檔,它通常所需要的內存比文檔模型方法(譬如 DOM 或 JDOM)要少。您還會(huì )發(fā)現,由于不需要遍歷文檔結構以獲取數據,因此用數據綁定方法訪(fǎng)問(wèn)程序內的數據要比用文檔模型方法快。最后,在輸入時(shí),一些特殊類(lèi)型的數據(譬如數字和日期)可以被轉換成內部表示,而不是保留為文本形式;這使應用程序可以更有效地使用數據值。
您可能想知道,如果數據綁定有這么多的好處,那么何時(shí)使用文檔模型方法呢?基本上在以下兩種主要情形下需要用文檔模型方法:
當應用程序確實(shí)要關(guān)注文檔結構的細節時(shí)。例如,如果您正在編寫(xiě)一個(gè) XML 文檔編輯器,則您會(huì )希望采用文檔模型,而不是使用數據綁定。 當正在處理的文檔不需要遵循固定的結構時(shí)。例如,對于實(shí)現常規的 XML 文檔數據庫,數據綁定不是一種很好的方法。
去年,我寫(xiě)了一篇文章,講述了如何使用 Castor 框架以進(jìn)行 Java 對象到 XML 文檔的映射數據綁定。我曾經(jīng)答應要寫(xiě)一篇后續文章,其中將探討代碼生成方法,包括介紹 JAXB,Java Community Process(JCP)正在開(kāi)發(fā) JAXB,它是用 Java 語(yǔ)言編寫(xiě)的、用于數據綁定的標準 API。就在較早的那篇文章發(fā)布不久,Sun 宣布對 JAXB 的方向做出了重大調整(請參閱
重新架構 JAXB)。由于這方面的變化,所以我想,為了更貼近最終的 JAXB 代碼,最好先不寫(xiě)這篇后續文章,現在,我很高興,終于可以寫(xiě)這篇文章了!
下面是一個(gè)微型字典,里面包含了我在本文中所使用的一些術(shù)語(yǔ):
文法(Grammar) 是用于定義一系列 XML 文檔結構的一套規則。其中一類(lèi)文法是 XML 規范所定義的文檔類(lèi)型定義(Document Type Definition,DTD)格式。另一類(lèi)日漸普及的文法是 XML Schema 規范所定義的 W3C XML Schema(Schema)格式。文法定義了哪些元素和屬性可以出現在文檔中,以及在文檔中元素是如何嵌套的(通常包括嵌套元素的次序和數目)。一些類(lèi)型的文法(譬如 Schema)還可以更進(jìn)一步,使字符數據內容與特定數據類(lèi)型甚至正則表達式相匹配。在本文中,我會(huì )常使用術(shù)語(yǔ) 描述, 將它作為引用一系列文檔的文法的非正式方法。
編組(Marshalling)是在內存中為對象生成 XML 表示的過(guò)程。與 Java 對象序列化一樣,這種表示需要包含所有依賴(lài)的對象:我們的主對象引用的對象、這些對象引用的對象等等。
數據分解(Unmarshalling) 是與編組相反的過(guò)程,在內存中根據 XML 表示構建一個(gè)對象(而且可能是鏈接對象的圖)。
在本文中,我將討論根據 XML 文檔文法生成 Java 語(yǔ)言代碼的五種 XML 數據綁定框架:JAXB、Castor、JBind、Quick 和 Zeus。它們都可以免費獲取,除了 JAXB 之外,其它四種框架都可以在開(kāi)放源碼和專(zhuān)利項目中使用。當前 JAXB 參考實(shí)現 beta 測試版的許可證只允許用于評估,但當它作為產(chǎn)品發(fā)行時(shí),這種情形很可能會(huì )改變。JAXB、Castor 和 JBind 都提供了根據 XML 文檔的 Schema 描述生成代碼,而 Quick 和 Zeus 根據 DTD 描述生成代碼。Castor 和 Quick 還支持將現有類(lèi)映射到 XML,以此作為另一種生成代碼的方法。
這些框架各有優(yōu)缺點(diǎn),所以我會(huì )試圖逐步指出每種框架所具有的最佳(和最差)特性。在第 2 部分,我將進(jìn)一步向您顯示這些框架如何對一些樣本文檔進(jìn)行處理,另外,還將探討,對于許多類(lèi)型的應用程序,現有的數據綁定框架怎么會(huì )缺乏一些重要的特性。
相對于我在以前文章中所描述的映射綁定方法,根據 Schema 或 DTD 文法生成 Java 語(yǔ)言代碼具有一些突出的優(yōu)點(diǎn)。使用生成的代碼,您可以確定數據對象被正確地鏈接到 XML 文檔,不象映射綁定方法,需要直接指定鏈接,并確保正確地涵蓋了所有的結構變體。在使用 Schema 時(shí),甚至可以利用文法所提供的類(lèi)型信息,用合適的數據類(lèi)型來(lái)生成代碼。
代碼生成方法也有一些不足之處。這種方法造成應用程序數據結構與 XML 文檔結構之間緊密耦合。另外,它還可能限定您使用簡(jiǎn)單的數據類(lèi)(沒(méi)有關(guān)聯(lián)行為的被動(dòng)數據容器),而不是真正的對象類(lèi),在編組和數據分解過(guò)程中,還可能限制應用數據的定制轉換的靈活性。在本文后面,我會(huì )權衡代碼生成和映射綁定這兩種方法(請參閱
映射綁定 vs. 代碼生成)。
對于將在第 2 部分中討論的性能測試,我用每一種數據綁定框架來(lái)生成代碼。用于性能測試的文檔包含模擬航班時(shí)刻表的信息。下面是一個(gè)樣本文檔,您可以感受一下其中的結構:
<?xml version="1.0"?><timetable> <carrier ident="AR"> <rating>9</rating> <URL>http://www.arcticairlines.com</URL> <name>Arctic Airlines</name> </carrier> <carrier ident="CA"> <rating>7</rating> <URL>http://www.combinedlines.com</URL> <name>Combined Airlines</name> </carrier> <airport ident="SEA"> <location>Seattle, WA</location> <name>Seattle-Tacoma International Airport</name> </airport> <airport ident="LAX"> <location>Los Angeles, CA</location> <name>Los Angeles International Airport</name> </airport> <route from="SEA" to="LAX"> <flight carrier="AR"> <number>426</number> <depart>6:23a</depart> <arrive>8:42a</arrive> </flight> <flight carrier="CA"> <number>833</number> <depart>8:10a</depart> <arrive>10:52a</arrive> </flight> <flight carrier="AR"> <number>433</number> <depart>9:00a</depart> <arrive>11:36a</arrive> </flight> </route> <route from="LAX" to="SEA"> <flight carrier="CA"> <number>311</number> <depart>7:45a</depart> <arrive>10:20a</arrive> </flight> <flight carrier="AR"> <number>593</number> <depart>9:27a</depart> <arrive>12:04p</arrive> </flight> <flight carrier="AR"> <number>102</number> <depart>12:30p</depart> <arrive>3:07p</arrive> </flight> </route></timetable>
圖 1 顯示了用于映射數據綁定到這些文檔的類(lèi)結構。為了進(jìn)行比較,我將在有關(guān)各個(gè)數據綁定框架章節中顯示生成的類(lèi)結構。這里包含的這些圖僅僅是所有情況的縮略圖;如果要看全圖,請單擊這個(gè)小圖像。
圖 1. 映射綁定類(lèi)圖(單擊進(jìn)行放大)
用于 XML 綁定的 Java API(Java API for XML Binding,JAXB)是一個(gè)處于不斷發(fā)展中的 Java 平臺數據綁定標準。Java Community Process 正在開(kāi)發(fā)作為“JSR-31 ― XML 數據綁定規范(XML Data Binding Specification)”的 JAXB。該項目始于 1999 年 8 月,其目的是定義一種方法,生成與 XML 結構相鏈接的 Java 語(yǔ)言代碼。最初打算在 2000 年第 2 季度發(fā)布,但最后在 JavaOne 2001 上宣布了初步的 Early Access(EA)版本,該版本在 2001 年 6 月向公眾發(fā)布。
JAXB 的 EA 版本基于具有創(chuàng )新意義的拉解析器(pull parser)設計,這種設計使驗證可以方便地構建到生成的數據分解代碼中。它根據 DTD 生成代碼,構建在解析 XML 文檔時(shí)自動(dòng)驗證 XML 文檔結構(而不是數據)的類(lèi)。我們期望這種方法能快速和有效地處理 XML 和 Java 語(yǔ)言對象之間的轉換,但 EA 代碼僅僅是部分實(shí)現,顯然在成為完整的實(shí)現之前,仍需要做大量工作。
專(zhuān)家組不久之后開(kāi)始收到關(guān)于 EA 發(fā)行版的反饋。作為對反饋意見(jiàn)的部分響應中,他們研究決定重新架構 JAXB,之后更新了網(wǎng)站,聲明 JAXB 在幾個(gè)方面正在得到增強。該站點(diǎn)還聲明,下一版本在 API 級上不與早期版本兼容 ― 但您仍然可以下載 EA 版本。
直到 2002 年 3 月,新體系結構的細節才公布于眾,在 JavaOne 上,Sun 宣布,作為在 JAXB 方面進(jìn)一步工作的基礎,實(shí)際上正在放棄 EA 代碼。它將被新設計所替代,在新設計中,共享了一些常見(jiàn)的功能,但新設計使用不兼容的 API 和內部體系結構。發(fā)展方向變化如此之大,讓我和那些對 EA 代碼有興趣的人們感到驚訝。
JAXB 項目的 SUN JSR 負責人 Joseph Fialli 把這么大的變化歸結為以下一些因素。主要問(wèn)題是擴展原有代碼庫以支持 W3C XML Schema 的復雜性。這是一個(gè)相當復雜的規范,以至于在批準之后的兩年多時(shí)間里,在所有平臺上,仍然只有少數幾個(gè)解析器能接近完全符合規范。最初的 JAXB 代碼需要實(shí)際對象來(lái)控制驗證,而且將這種方法擴展到 Schema 將耗費太多精力,以至于在合理的期限內無(wú)法實(shí)現這項工作。
為適應 Schema 而做出變更的同時(shí),專(zhuān)家組還決定重新考慮處理驗證的方法。原來(lái)的 JAXB 代碼無(wú)條件地驗證文檔的結構,如果發(fā)現錯誤,則拋出異常并中止處理。Fialli 說(shuō),在公眾的意見(jiàn)中,抱怨這種方法局限性太大、限制太嚴 ― 在一些情況下,用戶(hù)希望能夠一次檢查多個(gè)驗證錯誤,而在另一些情況下,則希望完全禁用驗證(或者由于性能原因,或者在編組沒(méi)有精確匹配文法的文檔時(shí))。新的 JAXB 體系結構能夠滿(mǎn)足這兩種需求。
最后,專(zhuān)家組決定放棄單個(gè)綁定框架運行時(shí)(就象在原來(lái) EA 發(fā)行版中所看的)的想法。而采用接口方法,其實(shí)質(zhì)是可以使用不同的數據綁定框架。這使用戶(hù)代碼可以在各框架之間進(jìn)行移植,而不需移植生成的類(lèi) ― 這些類(lèi)特定于專(zhuān)門(mén)的數據綁定框架,它們只能由該框架運行。強制性的 SAX 2.0 解析器支持替代了 EA 運行時(shí)中所使用的拉解析器方法,對于其它解析器(可能包括新的拉解析器,該解析器基于用于 XML 的流式 API,JSR 173 正在定義此 API),提供可選的特定于框架的支持,數據結構本身被更改為類(lèi) JavaBean 的數據對象,外部框架可以方便地操作此數據對象。
自 3 月以來(lái),JAXB 項目一直在朝著(zhù)這個(gè)新方向前進(jìn)。這一工作的第一個(gè)公開(kāi)成果是,去年夏天發(fā)布了該規范的新草案(但草案仍處于準備階段)。接著(zhù)在 10 月,Sun 提供了 JAXB 參考實(shí)現新的 beta 測試版,最終它會(huì )替代過(guò)時(shí)已久的 EA 版本。在這些文章中,我用這個(gè)最近的 beta 測試版進(jìn)行評估和性能測試。它直接根據 Schema 文檔描述進(jìn)行工作,生成與為文檔所定義的元素類(lèi)型和用法相匹配的類(lèi)的層次結構。該層次結構包括四種常規類(lèi)型的類(lèi):用于已定義類(lèi)型的接口、用于實(shí)際元素的接口和這兩組接口的實(shí)現。
圖 2. JAXB 接口類(lèi)圖(單擊進(jìn)行放大)
圖 3. JAXB 實(shí)現類(lèi)圖(單擊進(jìn)行放大)
從應用程序的角度來(lái)看,類(lèi)型接口是這些類(lèi)最有趣的部分。對于類(lèi)型內的數據,存在著(zhù) JavaBean 樣式的 get 方法和 set 方法集合。包含在類(lèi)型接口中的這些方法遵循 JAXB 規范所規定的規則,所以應用程序代碼可以安全地使用這些接口來(lái)訪(fǎng)問(wèn)所有數據,同時(shí)還保持了 JAXB 實(shí)現間的可移植性。這些接口使 JAXB 生成的代碼可以相當容易地與現有文檔一起使用。然而,構造和修改數據結構有點(diǎn)困難。因為使用接口,所以不能直接構造實(shí)例;而是必須使用工廠(chǎng)方法創(chuàng )建實(shí)例,然后使用類(lèi) JavaBean 的取值方法來(lái)填充數據值。
用 JAXB 根據 Schema 描述生成代碼非常簡(jiǎn)單。所提供的綁定編譯器 xjc 是一個(gè)命令行工具。它將 Schema 文檔作為輸入,將文件生成到指定的輸出包和目標目錄。其中所具有的選項還使用戶(hù)可以控制生成的代碼文件是否是只讀的,以及是否嚴格驗證 Schema 描述。
通過(guò)使用綁定聲明,JAXB 規范定義了一些方法來(lái)定制生成數據綁定的一些方面。包括:
用于控制所生成類(lèi)的名稱(chēng)和屬性的選項 指定由綁定所使用的現有實(shí)現類(lèi)的方法 允許(有限地)控制驗證處理和用于編組和數據分解的序列化器/反序列化器(serializer/deserializer)的選項
要么在實(shí)際的 Schema 文檔中以注釋形式嵌入這些定制,要么通過(guò)使用單獨的外部綁定聲明文檔來(lái)單獨提供這些定制。參考實(shí)現的當前 beta 測試版只支持第一種方法,但在以后的發(fā)行版中將支持使用外部綁定聲明文檔。
總體說(shuō)來(lái),JAXB 正成為一種功能強大而靈活的工具,它用于將 Java 語(yǔ)言代碼綁定到 W3C XML Schema 文法所定義的文檔。由于有可能批準將 JAXB 作為一個(gè) Java 平臺標準,因此它將會(huì )受到廣泛支持,而且在各實(shí)現之間移動(dòng)綁定應用程序會(huì )象在 servlet 引擎之間移動(dòng) Web 應用程序一樣容易(一般來(lái)講,很簡(jiǎn)單,但偶爾也會(huì )有一些波折)。
然而,JAXB 確實(shí)也有一些缺點(diǎn)。目前最大的局限是只有用于評估用途的許可證。在該產(chǎn)品發(fā)行版(目前計劃在這個(gè)季度發(fā)布)之前,JAXB 還無(wú)法用于實(shí)際項目中。另外,定制的程度也局限于只能應用到生成的代碼。在許多情形中,您可以為 JAXB 所定義的接口定義自己的實(shí)現類(lèi),但這些接口本身總是與 Schema 描述聯(lián)系在一起,不太可能進(jìn)行修改。
用于 XML 數據綁定的 Castor 框架支持映射綁定和生成綁定。在我的上一篇文章中,我討論了 Castor 映射綁定方法的一些特性。對于本文,我只討論根據 Schema 生成代碼,但在第 2 部分,我將研究這兩種方法的性能。請回顧以前的文章(請參閱
參考資料),了解有關(guān) Castor 中映射數據綁定工作方式的更多信息。
圖 4. Castor 生成的類(lèi)圖(單擊進(jìn)行放大)
在一些細節上,Castor 的代碼生成支持不同于 JAXB 方法,但在目的上,兩者非常相似。與使用 JAXB 一樣,Castor 向應用程序提供類(lèi) JavaBean 結構的數據模型。主要差別在于 Castor 避免使用接口,而是喜歡直接使用生成的實(shí)現類(lèi)。除了每個(gè)實(shí)現類(lèi),Castor 還生成描述符(descriptor)類(lèi),該類(lèi)包含綁定和驗證代碼。由于 Castor 使用具體的類(lèi),而不是接口,因此對于構造或修改文檔數據結構,它要比 JAXB 略微簡(jiǎn)單??梢?xún)H僅直接使用相應類(lèi)的構造函數,而不用通過(guò)工廠(chǎng)類(lèi)。
Castor 的當前 beta 測試版(我寫(xiě)這篇文章時(shí),該版本為 0.9.4.1)不支持在代碼生成中進(jìn)行任何實(shí)質(zhì)的定制,但這種情況有望得到改變。下一 beta 測試發(fā)行版預計將支持使用映射文件來(lái)控制代碼生成的各個(gè)方面。起初,在這些方面中,只支持類(lèi)名和包名,但從更長(cháng)遠來(lái)看,計劃將添加對用戶(hù)所提供的實(shí)現類(lèi)的支持。Castor 開(kāi)發(fā)人員還計劃在 Castor 中支持 JAXB,可能是通過(guò)使用某類(lèi)兼容性層來(lái)實(shí)現這一點(diǎn)。
用 Castor 根據 Schema 描述生成代碼與用 JAXB 一樣方便,使用的基本選項也一樣。Castor 確實(shí)使用一些附加的命令行參數選項,而且通過(guò)屬性文件設置,甚至提供了更多選項。這些選項主要用在一些特殊的情形中,但不包括象 JAXB 那樣通過(guò) Schema 文檔注釋提供對類(lèi)名和驗證的控制。
現在,用 Castor 來(lái)生成源代碼這種方法的主要缺點(diǎn)是對定制的支持有限。這種情形正在開(kāi)始發(fā)生轉變,可以用 Castor 的映射數據綁定方法來(lái)實(shí)現實(shí)質(zhì)的定制(見(jiàn)前一篇文章中的描述 ― 請參閱
參考資料),我期望最終在定制方面至少與源代碼生成方法具有同樣的靈活性。從長(cháng)遠來(lái)看,這將使它的適應性比 JAXB 更強。
Castor 按照 BSD 樣式的許可證進(jìn)行發(fā)布,完全可用于商業(yè)用途,而沒(méi)有什么重大限制。它看起來(lái)相當穩定,但每當遇到需要修正錯誤時(shí),您將需要更新到最新的開(kāi)發(fā)代碼(或等待新的 beta 測試發(fā)行版)。
與 JAXB 和 Castor 類(lèi)似,JBind 根據 XML 文檔的 Schema 描述來(lái)生成綁定代碼。盡管具有這種相同的性質(zhì),但實(shí)際上 JBind 的著(zhù)重點(diǎn)與前兩個(gè)大不相同。JBind 的主要創(chuàng )建者 Stefan Wachter 稱(chēng)此著(zhù)重點(diǎn)為“XML 代碼”,他是這樣描述它的:它將由 Schema 所描述的 XML 數據和由 Java 語(yǔ)言代碼所實(shí)現的行為組合在了一起。JAXB 和 Castor 更多地著(zhù)重于使 Java 語(yǔ)言應用程序方便地使用 XML,而 JBind 是圍繞 XML 構建應用程序代碼框架。一旦 JBind 構建好框架,則可以用自己的代碼擴展它來(lái)添加功能。
圖 5. JBind 生成的類(lèi)圖(單擊進(jìn)行放大)
JBind 還 可以 用于常規的數據綁定,在第 2 部分所討論的性能測試中,我就是以這種方式用 JBind 的。但這樣做略微有點(diǎn)笨拙,部分原因是由于 JBind 總是需要在運行時(shí)處理文檔的 Schema。如果實(shí)例文檔不直接引用相應的 Schema,則需要使用特殊的映射文件,或在讀取實(shí)例文檔之前,用手工將正確的 Schema 裝入到自己的代碼。目前的文檔不會(huì )真正向您顯示這是如何做的。與其它數據綁定框架相比,對處理綁定文檔結構的更改,JBind 也很?chē)栏?。通過(guò)使用 ListIterator ,可以刪除現有的元素對象,但只有使用生成的 create(創(chuàng )建)方法才能創(chuàng )建新的元素對象,這些方法自動(dòng)地將這些元素對象添加到現有內容的后面。
實(shí)質(zhì)上,JBind 采用與前面框架大不相同的方法來(lái)處理文檔數據。JBind 不生成 JavaBean 樣式的數據類(lèi)(但 JAXB 和 Castor 是這樣做的),而是將一切存儲在文檔模型(目前為 DOM 級別 2 實(shí)現)中,構建綁定代碼做為前端(facade)來(lái)訪(fǎng)問(wèn)存儲在文檔模型中的數據。這是一種非常有趣的方法,如果完全實(shí)現,這可能具有一些不錯的跨范例好處。目前這種方法所具有的唯一好處是在生成代碼中 。由于存儲機制相對于 JBind 的主旨是次要的,因此將來(lái)這種機制還可能會(huì )有所變動(dòng)。
JBind 所具有的好處是,在考慮過(guò)的所有數據綁定框架中,它支持 Schema 最徹底,并且提供
上面 所說(shuō)的 XPath 擴展。如果應用程序的核心是處理 XML 文檔,則使用由 JBind 構造的“XML 代碼”框架可能非常簡(jiǎn)單。對于一般的數據綁定用法,如果應用程序涉及到 XML 文檔,而不是其重點(diǎn)時(shí),則其它數據綁定方法可能會(huì )更簡(jiǎn)單些。由于數據分解時(shí)需要驗證以及由于文檔模型后端存儲機制(我將在第 2 部分更詳細地講述此問(wèn)題),因此與其它框架相比,JBind 還存在明顯的性能劣勢。JBind 是按照 Apache 樣式的許可證分發(fā)的,完全可用于商業(yè)用途。
Quick 文檔將自身描述為:不是作為處理 XML 的工具,而是作為對使用 XML 的 Java 語(yǔ)言的 擴展 。它基于位于 Java 平臺和 XML 之前的一系列開(kāi)發(fā)成果,在此過(guò)程中進(jìn)行了大量的重構工作。它確實(shí)為在 Java 平臺上使用 XML 提供了非常靈活的框架 ― 它所具有的靈活性遠遠超出了為寫(xiě)本文我所能夠了解和使用到的。
圖 6. Quick 生成的類(lèi)圖(單擊進(jìn)行放大)
Quick 的靈活性是有代價(jià)的。它使用一系列相當復雜的步驟來(lái)根據 DTD 文檔描述移到生成的代碼,在此過(guò)程中使用了作為中間步驟的三個(gè)獨立的綁定模式(不要與 W3C XML Schema 混淆)文檔:
QDML 文檔提供文檔描述,它大致相當于 DTD,不過(guò)添加了一些類(lèi)型和繼承。 QJML 文檔定義了 XML 到 Java 語(yǔ)言對象的綁定。 QIML 文件基本上是 QJML 的編譯形式,可以用它來(lái)生成實(shí)際的綁定代碼。
在第 2 部分 Quick 的性能測試中,我盡可能少地定制這些文件,但為了得到預期的最終結果,仍然需要做一些手工編輯。根據 DTD 文法生成 QDML 文件之后,必須編輯該文件來(lái)定義文檔的根元素,并為非 String 值(在這里,是幾個(gè) int )添加類(lèi)型信息。然后,運行程序來(lái)從 QDML 生成 QJML 文件,并編輯生成的 QJML,從而向引用添加類(lèi)型信息。其實(shí),并不真正需要這一步,但有了這一步,就可以用針對對象引用的特定類(lèi)型生成代碼(Castor 和 JAXB 代碼生成不支持該特性)。最后,運行該工具以從 QJML 生成 QIML 文件,然后運行代碼生成工具完成整個(gè)過(guò)程,從而獲得類(lèi) JavaBean 的對象類(lèi)和實(shí)際的綁定類(lèi)(用來(lái)從 XML 轉換到 Java 類(lèi)以及從 Java 類(lèi)轉換到 XML)。
再對這些文件進(jìn)行一些手工編輯,則可以避免生成用于該對象類(lèi)的新代碼,直接鏈接到 Castor 映射綁定所使用的現有的類(lèi)。這種可以使用現有類(lèi)的能力是一項功能非常強大的特性。由于模式文件很復雜,而且為了利用該特性必須做大量的更改,這些因素稍微降低了 Quick 的實(shí)用性,但這確實(shí)展示了 Quick 的靈活性。
靈活性是 Quick 最強大的特性。使用 Quick 的主要缺點(diǎn)是各種模式文件的復雜性,以及缺乏對 Schema 文法的支持。另外,使用 Quick 時(shí),獲得幫助看來(lái)也很困難:在論壇和郵件列表中,提出的問(wèn)題常常得不到任何響應。Quick 的許可證遵循 GNU 庫(GNU Library)或次通用公共許可證(Lessor General Public License,LGPL),這種許可證允許自由項目和商業(yè)項目使用該軟件。
象 Quick 一樣,Zeus 也根據 XML 文檔的 DTD 描述生成代碼。(現在正在開(kāi)發(fā)對 Schema 的支持,但目前處在開(kāi)發(fā)的 pre-alpha 階段)。這兩種框架只在這個(gè)方面是相似的。Quick 復雜而功能強大,而 Zeus 易于使用 ― 但功能非常有限。
圖 7. Zeus 生成的類(lèi)圖(單擊進(jìn)行放大)
在用法上,Zeus 代碼生成類(lèi)似于 JAXB 或 Castor,它提供了命令行工具來(lái)構造所需要的類(lèi)。與使用 JAXB 一樣,綁定使用接口。JAXB 使用工廠(chǎng)來(lái)構造對象類(lèi)的新實(shí)例,而 Zeus 通過(guò)原型使用生成的實(shí)現類(lèi)。用 Zeus 可以生成實(shí)現類(lèi)的子類(lèi),當對文檔進(jìn)行數據分解時(shí),使用子類(lèi)而不是使用生成類(lèi)。
不象前面所討論過(guò)的其它任何框架,Zeus 只支持 String ,而不支持其它類(lèi)型的值,譬如 int 或 Date 。它還缺乏對引用的支持,所以不能直接進(jìn)行數據分解或編組圖結構。這存在很大的局限性 ― 由于數據綁定可以利用類(lèi)型數據值和對象間鏈接的透明處理所提供的便利性,因此這給數據綁定帶來(lái)許多實(shí)用性。沒(méi)有這些特性的支持,Zeus 更象是一種經(jīng)過(guò)裁減的文檔模型,而不象是一個(gè)完整的數據綁定框架。
如果只使用 String 值,則考慮使用 Zeus 可能是不錯的選擇。使用 Zeus 的主要缺點(diǎn)是,提供的綁定形式有限,從整體上看,該項目進(jìn)展緩慢。與使用 Quick 一樣,您可能會(huì )發(fā)現難以找到問(wèn)題的答案。Zeus 按照 Enhydra 公共許可證 V1.1 進(jìn)行分發(fā),該許可證來(lái)自 Mozilla 公共許可證。
在本文中,我討論了幾種不同的框架,這些框架用于根據 XML 文檔文法生成 Java 語(yǔ)言代碼。這只是處理用于 Java 語(yǔ)言應用程序的 XML 數據綁定的一種方法。另一種主要方法是使用某種形式的映射綁定方法,在映射綁定方法中,構建自己的類(lèi)(或者最初根據文法來(lái)構建類(lèi),然后修改它們以滿(mǎn)足您的要求),并向綁定框架指定這些類(lèi)如何與 XML 文檔相關(guān)聯(lián)。每種方法有其利弊,它們都可能有最合適的用武之地。
代碼生成自動(dòng)構建反映 XML 文檔結構(換句話(huà)說(shuō),是 DTD 或 Schema 形式的文法)的類(lèi),這使您可以非??焖俚亻_(kāi)始使用文檔。當代碼生成基于 Schema 描述時(shí),所構造的類(lèi)可以包括完整的數據類(lèi)型信息(盡管用此方法存在一些問(wèn)題;許多 Schema 數據類(lèi)型在 Java 語(yǔ)言中沒(méi)有直接對應的數據類(lèi)型)。用代碼生成,您還可以將驗證構建進(jìn)所構造的類(lèi)中,從而要么自動(dòng)檢查值(當設置好它們時(shí)),要么按照需要檢查有效性。因此,您可以確保通過(guò)編組所生成的文檔總是與所期望的結構相匹配。
代碼生成方法的主要缺點(diǎn)是相對于其優(yōu)點(diǎn)而言。通過(guò)如此貼實(shí)地反映文檔結構,該方法使應用程序代碼和文檔結構之間緊密耦合。如果文檔結構發(fā)生變化,再需要重新生成代碼,并修改應用程序代碼以使用最終修改后的數據類(lèi)。
通常您還需要使用整個(gè)文檔結構,為了生成代碼,不易于對整個(gè)結構劃分子集。如果正在使用帶有許多可選組件的復雜結構(也許作為業(yè)界標準而定義的),而應用程序使用的文檔只用這些組件中的某個(gè)子集,則這可能會(huì )有問(wèn)題。對于這些框架中的大多數,使用它們時(shí)所生成的類(lèi)將總是與整個(gè)文檔結構匹配。您可能還需要在運行時(shí)包含所有這些生成的類(lèi),這取決于所使用的框架。對于應用程序,這導致代碼過(guò)度膨脹以及數據模型過(guò)度復雜。當然,通過(guò)編輯 DTD 或者 Schema 以消除不需要的組件,您可以避免這種情況 ― 但隨之而來(lái)當基本文法發(fā)生任何變化時(shí),都需要維護您的修改,這又帶來(lái)一組新的問(wèn)題。
映射綁定(譬如由 Castor 或 Quick 實(shí)現的映射綁定)比代碼生成具有更大的靈活性。使用真正的對象類(lèi)將數據和行為組合在一起。也可以在一定程度上解除對象類(lèi)與實(shí)際 XML 之間的耦合。修改映射定義(而不需要改變應用程序代碼)通常處理 XML 文檔結構中微小的變化。甚至可以用一種格式定義單獨的輸入和輸出映射來(lái)對文檔進(jìn)行數據分解,并用另一種格式編組它們。映射綁定的缺點(diǎn)是,在設置方面,它確實(shí)比生成代碼方法需要花費更多精力。
總之,對于所有應用程序,沒(méi)有一種方法總是最佳的。如果使用由 Schema 或 DTD 定義的穩定文檔結構,并且該結構適合應用程序的需要,則代碼生成方法可能是最佳方法。如果使用現有的 Java 語(yǔ)言類(lèi),或者希望使用類(lèi)的結構,該結構反映應用程序對數據用法,而不是 XML 文檔結構,則映射方法可能最佳。遺憾的是,當前大多數的開(kāi)發(fā)工作主要集中在代碼生成而不是映射。這種局限導致目前只有 Castor 和 Quick 才有這種映射方法。
在這第 1 部分中,我回顧了幾種主要的 XML 數據綁定框架,這些框架支持根據 XML 文檔描述生成 Java 語(yǔ)言代碼。這些框架在能力方面區別很大(在性能方面亦是如此,我將在第 2 部分中討論此問(wèn)題)。在基于 W3C XML Schema 定義的方法中,對于通用的數據綁定應用程序,Castor 提供了當前最佳支持?,F在已經(jīng)可以使用 Castor,目前人們正在擴展它以提供更好的生成代碼定制功能和更完善的 Schema 支持。人們還期望 Castor 將來(lái)支持即將出現的 JAXB 標準。
一旦 JAXB 作為產(chǎn)品發(fā)行版使用(當前的 beta 測試版許可證僅允許用于評估),則它看起來(lái)將是一項非常吸引人的選擇。目前 Castor 似乎比 JAXB 支持更多定制,但 JAXB 將提供可在各實(shí)現間進(jìn)行移植的好處。JAXB 也很可能被用在其它 Java 平臺標準(譬如用于 Web 服務(wù)的 JAX-RPC 標準)中,所以編寫(xiě) JAXB 的應用程序在將來(lái)可能在插件上兼容這些標準。
JBind 提供了最佳的 Schema 支持。如果應用程序適合“XML 代碼”模型,并且對性能的需求也不迫切,則 JBind 可能是很好的選擇,但對于使用一般的 XML 數據綁定,它顯得比較笨拙。Quick 提供了非常大的靈活性且功能強大,但它只支持 DTD 文法,而且使用起來(lái)相當復雜。Zeus 簡(jiǎn)單且容易,但它(與 Quick 一樣)只支持 DTD,另外,只允許訪(fǎng)問(wèn)作為 String 值的數據。
最后三個(gè)框架似乎更適合具有特殊需求的應用程序,而非一般用途。如果文檔只有 DTD 描述,而沒(méi)有模式,則出于這個(gè)原因,您可能希望嘗試 Quick 或 Zeus。對于大多數應用程序,這不是主要關(guān)心的問(wèn)題,因為有許多可用于將 DTD 轉換到模式的應用程序(盡管可能需要一些手工調整)。在 Castor 分發(fā)版中包括了一個(gè)這樣的程序(正如在 Castor XML FAQ 中所提到的, org.exolab.castor.xml.dtd.Converter )。
在第 2 部分中,我將展示這些數據綁定框架的性能結果,這些性能是在一些樣本文檔上使用這些框架測試出的。這些結果涉及了生成代碼方法和映射綁定方法,為了進(jìn)行比較,包含了文檔模型。我確實(shí)驚訝地看到……,但等等,現在我不能把 一切都告訴您。另外提醒您,在下個(gè)星期別錯過(guò)這個(gè)完全關(guān)于性能的“故事” ― 我保證您會(huì )找到值得一讀的結果!
您可以參閱本文在 developerWorks 全球站點(diǎn)上的
英文原文.
請參與本文的
論壇。(您也可以單擊本文頂部或底部的 討論來(lái)訪(fǎng)問(wèn)該論壇)。
如果要了解有關(guān) XML 的背景知識,請嘗試參加 developerWorks教程
Introduction to XML(2002 年 8 月)。
閱讀作者以前的文章“
Data binding with Castor”,這篇文章講述了 Castor 的映射數據綁定技術(shù)( developerWorks,2002 年 4 月)。
瀏覽作者以前的 developerWorks文章,
性能(2001 年 9 月)和
用法(2002 年 2 月),這兩篇文章比較了幾種 Java XML 文檔模型。
閱讀 Brett McLaughlin 的文章“
Converting between Java objects and XML with Quick”,該文概述了 Quick,并向您展示了如何使用該框架來(lái)快速方便地將 Java 數據轉換成 XML 文檔,而不需要其它數據綁定框架所需的類(lèi)生成語(yǔ)義( developerWorks,2002 年 8 月)。
有關(guān)對象關(guān)系數據綁定的基礎知識簡(jiǎn)介,請閱讀“
Getting started with Castor JDO”一文(由 Bruce Snyder 撰寫(xiě), developerWorks,2002 年 8 月)。
數據綁定框架
查找更多有關(guān)
Java Architecture for XML Binding (JAXB)方面的內容,JAXB 是一個(gè)處于正在發(fā)展中的 Java 平臺數據綁定標準。
更進(jìn)一步了解
Castor框架,它支持映射綁定和生成綁定。
了解
JBind,它主要偏重于圍繞 XML 構建應用程序代碼框架,不太注重使 Java 語(yǔ)言應用程序方便地使用 XML。
Quick 框架是基于 Java 平臺和 XML 出現之前的一系列開(kāi)發(fā)成果。它為在 Java 平臺上使用 XML 提供了極其靈活的框架。
研究
Zeus的方方面面,它(類(lèi)似于 Quick)根據 XML 文檔的 DTD 描述來(lái)生成代碼,使用 Zeus 要比使用 Quick 簡(jiǎn)單,但同時(shí) Zeus 要更有限。
其它鏈接
閱讀有關(guān)
Java Technology and XML之間的相互影響。
參閱
JSR 31 — XML 數據綁定規范(XML Data Binding Specification)。
在 developerWorks
XML和
Java 技術(shù)專(zhuān)區查找更多有關(guān)本文所涵蓋的技術(shù)信息。
IBM WebSphere Studio提供了一套使 XML 開(kāi)發(fā)自動(dòng)化的工具(用 Java 和其它語(yǔ)言進(jìn)行開(kāi)發(fā))。它與
WebSphere Application Server緊密集成,但它也可以與其它 J2EE 服務(wù)器一起使用。
了解如何成為一名
XML 及其相關(guān)技術(shù)的 IBM 認證開(kāi)發(fā)人員。
關(guān)于作者
Dennis Sosnoski(
dms@sosnoski.com )是西雅圖地區的 Java 技術(shù)咨詢(xún)公司
Sosnoski Software Solutions, Inc. 的創(chuàng )始人和首席顧問(wèn),他是 J2EE、XML 和 Web 服務(wù)支持方面的專(zhuān)家。Dennis 有 30 多年的專(zhuān)業(yè)軟件開(kāi)發(fā)經(jīng)驗,最近幾年致力于服務(wù)器端的 Java 技術(shù)。他經(jīng)常在全國性的會(huì )議上就 Java 中的 XML 和 J2EE 技術(shù)發(fā)表言論,并主持
Seattle Java-XML SIG。