前言
上一篇文章講到了使用Java原生的序列化的方式來表示一個物件。總結一下這種物件表示方式的優缺點:
1、純粹的Java環境下這種方式可以很好地工作,因為它是Java自帶的,也不需要第三方的Jar包的支援
2、多語言環境下,使用Java序列化方式進行儲存後,很難用其他語言還原出結果
3、佔用的位元組數比較大,而且序列化、反序列化效率也不高
前面也提到過,物件表示有各種各樣的方式,序列化只是其中的一種而已。表示一個物件的目的無非就是為了物件<---->IO之間相互認識,至於怎麼認識,那就有很多選擇了。除了之前講過的序列化,還可以選擇將資料JSON化、XML化。當前也有比較好用的序列化工具,比如Google的protobuf。這篇文章主要想寫一下對物件進行XML化,使用的是XStream。至於為什麼選擇寫XStream,因為工作用,呵呵。
利用XStream表示一個物件
XStream就是一種Java物件和XML之間相互轉換的工具,沒有什麼可以特別介紹的,XStream提供了所有的基礎型別、陣列、集合等型別直接轉換的支援。XStream中的核心類就是XStream類,一般來說熟悉這個類就夠用了。使用XStream需要用到兩個第三方jar包,我工程裡面使用的xstream-1.4.jar和kxml2.jar。一開始我在玩XStream以為只需要前一個jar包就可以了,結果執行的時候各種錯誤,所以這裡要注意一下。首先寫一個最簡單的程式:
1 public class XmlObject 2 { 3 private int count; 4 private double price; 5 private String phone; 6 7 public XmlObject(int count, double price, String phone) 8 { 9 this.count = count; 10 this.price = price; 11 this.phone = phone; 12 } 13 14 public String toString() 15 { 16 return "count = " + count + ", price = " + price + ", phone = " + phone; 17 } 18 }
1 public static void main(String[] args) 2 { 3 XStream xs = new XStream(); 4 XmlObject xo = new XmlObject(10, 10.5, "110"); 5 String str = xs.toXML(xo); 6 System.out.println(str); 7 }
看一下執行結果:
<com.xrq.test.XmlObject> <count>10</count> <price>10.5</price> <phone>110</phone> </com.xrq.test.XmlObject>
是的,這麼簡單,就把一個物件表示出來了。這時候,想怎麼操作這個str都無所謂了,可以用一個FileWriter把這個str存入磁碟,也可以用一個HttpClient傳輸這串str進行網路通訊。
設定一下別名
OK,看到上面這串輸出,可能有些人不爽了,“com.xrq.test.XmlObject”這麼麻煩,能不能表示地簡單點啊?當然可以,而且不僅可以對物件重新命名,物件中的屬性也可以:
1 public static void main(String[] args) 2 { 3 XStream xs = new XStream(); 4 XmlObject xo = new XmlObject(10, 10.5, "110"); 5 xs.alias("XmlObject", XmlObject.class); 6 xs.aliasField("Count", XmlObject.class, "count"); 7 xs.aliasField("Price", XmlObject.class, "price"); 8 xs.aliasField("Phone", XmlObject.class, "phone"); 9 String str = xs.toXML(xo); 10 System.out.println(str); 11 }
看一下執行結果:
<XmlObject> <Count>10</Count> <Price>10.5</Price> <Phone>110</Phone> </XmlObject>
看到,物件名變了,物件中的屬性名也變化了。
XStream支援陣列和集合
之前說過,XStream不僅支援基本資料型別,也支援陣列、集合,把程式修改一下再看一下:
1 public class XmlObject 2 { 3 private int[] counts; 4 private List<String> phones; 5 private Map<String, Date> calendar; 6 7 public XmlObject(int[] counts, List<String> phones, Map<String, Date> calendar) 8 { 9 this.counts = counts; 10 this.phones = phones; 11 this.calendar = calendar; 12 } 13 14 public String toString() 15 { 16 return "count = " + counts + ", phones = " + phones + ", calendar = " + calendar; 17 } 18 }
1 public static void main(String[] args) 2 { 3 int[] counts = {10, 11, 12}; 4 List<String> phones = new ArrayList<String>(); 5 phones.add("110"); 6 phones.add("119"); 7 phones.add("120"); 8 Map<String, Date> calendar = new HashMap<String, Date>(); 9 calendar.put("1", new Date()); 10 calendar.put("2", new Date()); 11 XStream xs = new XStream(); 12 XmlObject xo = new XmlObject(counts, phones, calendar); 13 xs.alias("XmlObject", XmlObject.class); 14 xs.aliasField("Count", XmlObject.class, "counts"); 15 xs.aliasField("Phones", XmlObject.class, "phones"); 16 xs.aliasField("Calendar", XmlObject.class, "calendar"); 17 String str = xs.toXML(xo); 18 System.out.println(str); 19 }
看一下執行結果
<XmlObject> <Count> <int>10</int> <int>11</int> <int>12</int> </Count> <Phones> <string>110</string> <string>119</string> <string>120</string> </Phones> <Calendar> <entry> <string>2</string> <date>2015-09-20 08:23:13.665 UTC</date> </entry> <entry> <string>1</string> <date>2015-09-20 08:23:13.665 UTC</date> </entry> </Calendar> </XmlObject>
看到string、date這兩個開頭字母都是小寫的有點不爽?沒關係,依樣畫葫蘆,main函式裡面加上這兩句就可以了
xs.alias("String", String.class); xs.alias("Date", Date.class);
XML轉換成Java物件
迴歸前面最簡單的那個XmlObject,看一下把XML轉換為Java物件,也很簡單,利用fromXml()方法就可以了。自己構造一個xml字串:
1 public static void main(String[] args) 2 { 3 XStream xs = new XStream(); 4 String xmlStr = "<com.xrq.test.XmlObject><count>10</count><price>10.5</price><phone>110</phone></com.xrq.test.XmlObject>"; 5 XmlObject xo = (XmlObject)xs.fromXML(xmlStr); 6 System.out.println(xo); 7 }
執行結果就不貼了,就是XmlObject三個屬性的toString()而已。注意這裡用的沒有alias過的“com.xrq.test.XmlObject”,要是直接用“XmlObject”會報“com.thoughtworks.xstream.mapper.CannotResolveClassException”這個異常。解決方案很簡單,第5行前面加上xs.alias("XmlObject", XmlObject.class);就好了。
後記
文章主要寫了對於XStream的使用,一般來說,XStream用到這個程度也就夠了。XStream使用非常容易,而且XML化之後的資料可讀性強。不過在github上看到了一篇文章https://github.com/eishay/jvm-serializers/wiki,看得出XML的缺點主要在於還是解析的時候效率低了一些,而且為了可讀性,XML也引入了一些冗餘的文字資訊從而造成了一定的空間開銷。但是,無論如何,操作量不大的場景下 ,個人還是推薦使用XStream。