JAXB –新手的观点,第1部分
我知道你們很多人已經(jīng)在想什么了,所以讓我們擺脫它:“ JAXB? 如XML? 來吧,所有很棒的孩子都在使用JSON。”
關(guān)于XML與JSON的爭論以及許多促成它的論據(jù)都已被很好地記錄在案。 我不會(huì)花很多時(shí)間在這里重新整理它們。 我相信每種格式都有其用途,但是即使您處在“從未有過XML”陣營中,您仍然可能想繼續(xù)閱讀,因?yàn)槲矣懻摰挠^察和技術(shù)應(yīng)該同樣適用于與Jackson進(jìn)行JSON數(shù)據(jù)綁定(或類似工具)。
在第1部分中,我描述了一種簡單的使用模式,該模式將JAXB的數(shù)據(jù)綁定功能與JPA配對(duì)。 當(dāng)然,兩者之間的交互并不總是那么簡單,因此在第2部分中,我將研究如何解決可能遇到的一些復(fù)雜問題。
問題
在我當(dāng)前的項(xiàng)目中,我們正在構(gòu)建一套Java應(yīng)用程序,以管理制造過程中物料的轉(zhuǎn)移。 我們決定“從外而內(nèi)”構(gòu)建,以在任何給定的迭代之后促進(jìn)面向用戶的演示。 因此,在第一個(gè)迭代中,我們使用硬編碼的虛擬數(shù)據(jù)構(gòu)建了一些屏幕。 然后,在每次后續(xù)迭代中,我們都會(huì)在屏幕后面添加更多基礎(chǔ)架構(gòu)和邏輯。
為了使早期的演示更具交互性,我們決定為中央應(yīng)用程序創(chuàng)建一個(gè)“測試控制臺(tái)”。 一個(gè)人在控制臺(tái)上鍵入命令可以模擬系統(tǒng)“已實(shí)現(xiàn)網(wǎng)絡(luò)”部分的行為。 借助Antlr 4之類的工具可以簡化命令解析,構(gòu)建控制臺(tái)的成本是適中的,并且我們認(rèn)為使用控制臺(tái)進(jìn)行測試和診斷具有長期價(jià)值。
我們已經(jīng)達(dá)到了需要由另一個(gè)應(yīng)用程序的數(shù)據(jù)來驅(qū)動(dòng)系統(tǒng)行為的地步。 負(fù)責(zé)創(chuàng)建和維護(hù)此數(shù)據(jù)的“其他應(yīng)用”尚未編寫,并且不會(huì)使用一段時(shí)間,因此我們需要一種通過控制臺(tái)加載示例數(shù)據(jù)的方法。
選件
本質(zhì)上,我們的任務(wù)是構(gòu)建(或利用)數(shù)據(jù)加載器。 我們選擇XML作為文件的可能格式,然后瀏覽我們的團(tuán)隊(duì)通常會(huì)熟悉的工具列表。
DBUnit具有數(shù)據(jù)加載功能(旨在設(shè)置可重復(fù)的測試條件)。 它支持兩種不同的XML模式(“平面”和“完整”),每種模式顯然都是面向表的。 它還提供了替換變量,因此我們可以構(gòu)建模板文件并允許控制臺(tái)輸入設(shè)置最終值。
我對(duì)以這種方式使用單元測試工具有些保留,但是在團(tuán)隊(duì)的箭袋中,箭頭可能是最合適的。 不管是好是壞,我第一次嘗試使用它都沒有成功(結(jié)果是我看的是DBUnit API的錯(cuò)誤部分),這使我想出了一些新的思路。
我們已經(jīng)有一種方法(即Hibernate)將數(shù)據(jù)推送到我們的數(shù)據(jù)庫中。 因此,當(dāng)我用“如何從XML文檔創(chuàng)建實(shí)體實(shí)例”來表述問題時(shí),JAXB顯然是競爭者。 我很高興發(fā)現(xiàn)Java附帶了JAXB實(shí)現(xiàn),因此我開始嘗試一下。
新人的觀點(diǎn)
從未使用過JAXB,所以我開始進(jìn)行一些研究。 我發(fā)現(xiàn)的許多材料都涉及從XML模式生成Java類。 這不足為奇-這是該工具可以完成的大部分工作-但就我而言,我想將數(shù)據(jù)綁定到現(xiàn)有的Hibernate映射域類。 這導(dǎo)致可能會(huì)更加令人驚訝:我發(fā)現(xiàn)一些最全面的教程似乎并沒有預(yù)料到這種用法。 我認(rèn)為這很好地說明了您對(duì)工具的初步假設(shè)可以影響您的想法和使用方式。
如果像幾個(gè)在線資源一樣,首先將JAXB與DOM進(jìn)行比較,那么將編組操作的輸出視為需要遍歷和處理的文檔樹是很自然的,也許會(huì)將相關(guān)數(shù)據(jù)復(fù)制到并行的層次結(jié)構(gòu)中。域?qū)ο蟆?遍歷和處理(至少在概念上)可能比使用DOM樹要容易(但從概念上來說),但是要權(quán)衡,您必須保持兩個(gè)類的層次結(jié)構(gòu)直,這需要謹(jǐn)慎的命名約定。
毫無疑問,用例恰恰是必要的,但該工具不僅限于這種方法。 如果您相反地比較JAXB和Hibernate(作為將數(shù)據(jù)從外部源加載到您的域?qū)ο笾械囊环N方式),那么自然會(huì)問“為什么我不能同時(shí)使用一組域?qū)ο?#xff1f;” 您至少可以在某些時(shí)候稍加注意。
簡單案例
在這些示例中,我將直接使用JAXB API。 我們只需撥打幾個(gè)簡單的電話即可完成我們的任務(wù),因此這相當(dāng)簡單。 值得注意的是,Spring確實(shí)也提供JAXB集成,尤其是如果您在整個(gè)應(yīng)用程序中都使用Spring,則它提供的配置方法可能是更可取的。
假設(shè)您有一個(gè)EMPLOYEE表。 每個(gè)員工都有唯一的數(shù)字ID和名稱。 如果將注釋用于ORM映射數(shù)據(jù),則可能具有如下域類:
@Entity @Table(name=”EMPLOYEE”) public class Employee {@Id@Column(name=”EMPLOYEE_ID”)private Integer employeeId;@Column(name=”FIRST_NAME”)private String firstName;@Column(name=”LAST_NAME”)private String lastName;// … getters and setters … };現(xiàn)在,我們要讓用戶提供一個(gè)Employee.xml數(shù)據(jù)文件。 假設(shè)我們沒有需要遵循的特定XML模式,那么我們不妨看看JAXB對(duì)類的默認(rèn)處理是什么。 因此,我們將從最小的步驟開始,以將一個(gè)Employee實(shí)例“封送”到XML文檔中。 如果對(duì)結(jié)果文檔的外觀感到滿意,我們將交換解組代碼; 如果沒有,我們可以考慮自定義映射。
首先,我們需要配置一個(gè)JAXBContext實(shí)例以與我們的域類一起使用。
JAXBContext jaxb = JAXBContext.newInstance(Employee.class);順便說一句,我們可以傳入包含類的包的名稱,而不是將類對(duì)象傳遞給newInstance(),只要每個(gè)包都包含一個(gè)jaxb.in??dex文件,該文件列出了要使用的類或ObjectFactory類,以及用于創(chuàng)建域類(和/或包裝它們的JAXBElements)實(shí)例的方法。 如果您需要大量不相關(guān)的域類的XML映射,則此方法可能更可取。
JAXBContext具有創(chuàng)建編組器(創(chuàng)建表示對(duì)象的XML文檔)和解組器(實(shí)例化對(duì)象并從XML文檔中的數(shù)據(jù)初始化它們)的方法。 我們可以像這樣檢查Employee類的默認(rèn)映射:
Employee employee = new Employee();employee.setEmployeeId(37);employee.setFirstName(“Dave”);employee.setLastName(“Lister”);Marshaller marshaller = jaxb.createMarshaller();marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(employee, System.out);(嚴(yán)格來說,setProperty()調(diào)用不是必需的,但會(huì)使輸出更易于理解。)如果嘗試運(yùn)行此代碼,則會(huì)收到異常消息,告訴我們尚未識(shí)別出根元素。 為了解決這個(gè)問題,我們將@XmlRootElement批注添加到Employee類中。
@XmlRootElement @Entity @Table(name=”EMPLOYEE”) public class Employee {@Id@Column(name=”EMPLOYEE_ID”)private Integer employeeId;@Column(name=”FIRST_NAME”)private String firstName;@Column(name=”LAST_NAME”)private String lastName;// … getters and setters … };默認(rèn)情況下,編組器將映射每個(gè)公共bean屬性(getter / setter對(duì))和每個(gè)公共字段。 因此,如果我們的Employee類具有您期望的getter和setter,那么我們的輸出應(yīng)類似于以下內(nèi)容:
<?xml version=”1.0” encoding=”UTF-8” standalone=”yes”?> <employee><employeeId>37</employeeId><firstName>Dave</firstName><lastName>Lister</lastName> </employee>請(qǐng)注意,下面的元素將采用任意順序。 (在我的測試中,這是按字母順序排列的。)在這種情況下,效果很好,但是如果沒有,我們可以使用@XmlType注釋強(qiáng)制執(zhí)行該順序。 默認(rèn)情況下,解組器將以任何順序獲取元素。
JAXB很高興不了解JPA批注,而Hibernate(或您可能使用的任何JPA提供程序)將不理會(huì)JAXB批注,因此,我們現(xiàn)在可以通過簡單地要求JAXB從文件中解組數(shù)據(jù)來將XML文件中的數(shù)據(jù)加載到數(shù)據(jù)庫中,將結(jié)果對(duì)象傳遞給JPA提供程序。 解組代碼如下所示:
JAXBContext jaxb = JAXBContext.newInstance(Employee.class); Unmarshaller unmarshaller = jaxb.createUnmarshaller(); File xmlFile = /* … */; Employee employee = unmarshaller.unmarshal(xmlFile);默認(rèn)情況下,如果從XML中省略了表示bean屬性之一的元素,則不會(huì)設(shè)置該屬性。 因此,例如,如果我們的JPA映射包括自動(dòng)生成employeeId,則<employee>元素僅需要包含<firstName>和<lastName>。
好…
從理論上講,就是這樣。 (如果您知道理論和實(shí)踐之間的區(qū)別,則要額外加分。)幾個(gè)注釋和可能的十幾行代碼足以讓您入門。 另外一個(gè)好處是,您可以在一個(gè)帶注釋的.java文件中查看所有數(shù)據(jù)表示形式(XML,數(shù)據(jù)庫和Java對(duì)象)之間的關(guān)系。
不太好…
上面的例子很簡單,可以涵蓋大量的基本用例。 但是大多數(shù)真實(shí)的數(shù)據(jù)模型都包含一對(duì)多關(guān)系和組合鍵之類的東西,它們?cè)黾恿四赡軙?huì)或可能不會(huì)看到的皺紋。 在第2部分(計(jì)劃于2014年8月25日)中,我將介紹我遇到的一些復(fù)雜問題,并討論解決每個(gè)復(fù)雜問題的合理簡單方法。
翻譯自: https://www.javacodegeeks.com/2014/07/jaxb-a-newcomers-perspective-part-1.html
總結(jié)
以上是生活随笔為你收集整理的JAXB –新手的观点,第1部分的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 《碧海黑帆》游戏失去第三位创意总监,育碧
- 下一篇: 比萨问题–建造者与装饰者