跨系統的調用目前無(wú)疑是 WebService 的天下,指的是通過(guò) HTTP 請求方式獲得 XML 或 JSON 數據的方式,RESTFul 也得到了很好的應用。規范意義上的 Soap 調用不知道還不多不多,反正當年用過(guò)的 Corba 鮮有耳聞了,就像很多人對 EJB2 不會(huì )有概念一樣。
Java 在調用 WebService 獲得了 XML 之后,接下來(lái)一種常見(jiàn)的處理方式就是把它轉換成相應的 JavaBean,再丟給其他組件像 Jsp 標簽,FreeMarker 等去就很流暢了。關(guān)于 XML 與 JavaBean 互相轉換有兩個(gè)操作叫做:Marshaller 和 Unmarshaller,還沒(méi)見(jiàn)一個(gè)權威的翻譯,大概就是編組與反編組,意義如同序列化與反序列化。也就是由 JavaBean 到 XML 叫做 Marshal,由 XML 到 Java 叫做 Unmarshal。
通常從 XML 到 JavaBean 的轉換機會(huì )大的多,所以我主要也是研究了下如何把 XML 映射成 JavaBean,雖然現在的工具一樣也都支持這兩個(gè)方向的轉換。有許多組件可以做到,像 JAXB(Java Architecture for XML Binding)、XMLBeans、JiBX、Castor。前面這些工具都提供了工具根據 XML 數據和相應的 Schma 產(chǎn)生相應 Java 類(lèi)的功能,我還是喜歡先入為主的方式,自己手工寫(xiě)好了 JavaBean 主動(dòng)去包容 XML 數據。
JAXB是Java EE平臺的API之一,同時(shí)是Java Web服務(wù)開(kāi)發(fā)包(JWSDP)的一部分。 JAXB也是Web服務(wù)互操作性技術(shù)(WSIT)的基礎之一. JAXB是J2SE1.6的一部分。JAXB 1.0是在Java社群過(guò)程中作為JSR 31開(kāi)發(fā)出來(lái)的。JAXB 2.0是作為JSR 222開(kāi)發(fā)的。
下面看個(gè) JAXB 把 XML 轉換為 JavaBean 的例子,本例由一個(gè) XML 文件和四個(gè)類(lèi)組成,所涵蓋到的內容有,元素和屬性的映射,Namespace 的使用,以及一個(gè)自定義的 XmlAdapter 類(lèi)。
1. XML 文件,users.xml:
01 02 03 04 05 06 07 08 09 10 11 12 13 | <?xml version="1.0" encoding="UTF-8"?><users xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> <user i:type="worker"> <id>1</id> <name>Unmi</name> <time>2010-11-18T21:57:15.07</time> </user> <user i:type="yuan"> <id>2</id> <name>She</name> <time>2010-10-18T21:20:15.25</time> </user></users> |
2. 兩個(gè) JavaBean,為獲得上面數據組裝到 JavaBean,我用了兩個(gè) Java 類(lèi),分別是 UserList.java 和 User.java。
UserList.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | package cc.unmi.jaxb;import java.util.List;import javax.xml.bind.annotation.XmlElement;import javax.xml.bind.annotation.XmlRootElement;/** * @author Unmi CreateTime: Apr 21, 2011 */@XmlRootElement(name = "users")public class UserList { List<User> users; @XmlElement(name = "user") public List<User> getUsers() { return users; } public void setUsers(List<User> users) { this.users = users; }} |
為類(lèi)用 XmlRootElement 注解了這是個(gè)根元素,對應于 XML 中的 users 元素,并在它的屬性 users 的 getter 方法上應用了 XmlElement,節點(diǎn)名為 user。
User.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 | package cc.unmi.jaxb;import java.util.Date;import javax.xml.bind.annotation.XmlAttribute;import javax.xml.bind.annotation.XmlElement;import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;/** * @author Unmi * CreateTime: Apr 21, 2011 */public class User { private int id; private String type; private String name; private Date date; @XmlElement(name = "id") public int getId() { return id; } public void setId(int id) { this.id = id; } @XmlElement(name = "name") public String getName() { return name; } public void setName(String name) { this.name = name; } @XmlElement(name = "time") @XmlJavaTypeAdapter(DateAdapter.class) public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } @XmlAttribute(name = "type", namespace = "http://www.w3.org/2001/XMLSchema-instance") public String getType() { return type; } public void setType(String type) { this.type = type; } public String toString() { return id + ":" + name + ":" + type + ":" + date; }} |
類(lèi)不需要進(jìn)行注解,同樣是對屬性的 getter 方法注解標識其對應于 XML 上的什么節點(diǎn)。對于時(shí)間節點(diǎn)用了自定義的 DateAdapter 在字符串與 Date 類(lèi)型間轉換。注意 getType() 的注解,用的是 XmlAttribute,并帶有命名空間,這里的 namespace 不能寫(xiě)成 "i" 的。
DateAdapter.java
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | package cc.unmi.jaxb;import java.text.DateFormat;import java.text.SimpleDateFormat;import java.util.Date;import javax.xml.bind.annotation.adapters.XmlAdapter;public class DateAdapter extends XmlAdapter<String, Date> { private DateFormat df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SS"); public Date unmarshal(String val) throws Exception { if (val == null) { return null; } return df.parse(val); } public String marshal(Date val) throws Exception { if (val == null) { return null; } return df.format(val); }} |
看到分別對應于 unmarshal 和 marshal 的兩個(gè)方法,寫(xiě)過(guò) Struts 或 Hibernate 的 TypeHandler 會(huì )很容易理解的。
Client.java,客戶(hù)端調用代碼:
01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 | package cc.unmi.jaxb;import java.net.URL;import javax.xml.bind.JAXBContext;import javax.xml.bind.Unmarshaller;/** * @author Unmi * CreateTime: Apr 21, 2011 */public class Client { public static void main(String[] args) throws Exception { JAXBContext context = JAXBContext.newInstance(UserList.class); Unmarshaller unmarshaller = context.createUnmarshaller(); URL xmlFileUrl = ClassLoader.getSystemResource("users.xml"); UserList userList = (UserList) unmarshaller.unmarshal(xmlFileUrl); System.out.println(userList.getUsers().get(0).getName()); }} |
執行后看到控制臺如下輸出就說(shuō)明了各個(gè)屬性都工作正常:
1:Unmi:worker:Thu Nov 18 21:57:15 CST 2010
特性說(shuō)明:
1. 用注解的方式,可聲明在 setter/getter 方法上,也可以在屬性上,但不能同時(shí)對一個(gè)屬性注解兩次,否則就會(huì )報錯:@javax.xml.bind.annotation.XmlElement annotation is found on two places; one would be suffice.
如果只在屬性上用 XmlElement 注解,也會(huì )出錯:Class has two properties of the same name "id". 此時(shí)得在對應的 getter 或 setter 方法加上注解:@XmlTransient。
2. 如果取一個(gè) List 數據必須聲明出一個(gè)相應的 XxxList 類(lèi),其中包含一個(gè) List 屬性,這里的 XxxList 有點(diǎn)多余。還不清楚如何在業(yè)務(wù)類(lèi)中直接映射出 List<User> 屬性。
3. 有 Namespace 時(shí),需要寫(xiě)全 namespace,如namespace=http://www.w3.org/2001/XMLSchema-instance. 這有點(diǎn)啰唆。
4. 使用還是很簡(jiǎn)單,可以定義自己的類(lèi)型轉換類(lèi),像這里的 DateAdapter
5. 如果更深層次的 XML 結構,只需依循著(zhù) XPATH 用進(jìn)行更深度的注解類(lèi)的屬性。理解了上面的例子,對于只表示一個(gè) Java 對象的 XML 的映射方法就很簡(jiǎn)單了。
6. 因為注解的方法,如果一個(gè) Bean 去映射多個(gè) XML 時(shí),就有困難,比如節點(diǎn)名變了,但映射的是同一個(gè)屬性時(shí)這個(gè) JavaBean 類(lèi)不好重用。
7. Bean 需要一個(gè)默認構造函數,對象是通過(guò)默認構造函數創(chuàng )建的,屬性要通過(guò) setter 方法去設置,所以可以在構造方法和 setter 方法中對實(shí)例作某些修飾。
8. 更多注解的使用請瀏覽下包 javax.xml.bind.annotation 中的所有注解類(lèi),像 XmlElementWrapper、XmlList、DomHandler 等,都會(huì )有用處的。在 unmarshl 時(shí)可支持更多的輸入源類(lèi)型,最后見(jiàn)下幾個(gè)圖:



資料:1. http://stackoverflow.com 上搜索有關(guān) jaxb 的資源
2. 使用JAXB將XML Schema綁定到Java類(lèi)
3. 用JAXB生成一個(gè)XML文檔
4. Java Architecture for XML Binding (JAXB)
5. http://jaxb.java.net/
本文鏈接 http://unmi.cc/jaxb-xml-javabean-start, 來(lái)自 隔葉黃鶯 Unmi Blog
[版權聲明]本站內文章,如未特別注明,均系原創(chuàng )或翻譯之作,本人 Unmi 保留一切權利。本站原創(chuàng )及譯作未經(jīng)本人許可,不得用于商業(yè)用途及傳統媒體。網(wǎng)絡(luò )媒體可隨意轉載,或以此為基礎進(jìn)行演譯,但務(wù)必以鏈接形式注明原始出處和作者信息,否則屬于侵權行為。另對本站轉載他處文章,俱有說(shuō)明,如有侵權請聯(lián)系本人,本人將會(huì )在第一時(shí)間刪除侵權文章。及此說(shuō)明,重之之重。
聯(lián)系客服