Merlin 的一種新功能在 Sun 的 Swing Connection 中以各種形式出現已有一段時間了,實際上它首次被討論是在 1999 年的 JavaOne 展示會上。這個功能可以將 JavaBean 組件狀態長期持久地保存在 XML 文檔中。序列化工作適合短期編組的需要(對於 CORBA 和 RMI)或適合將狀態信息保存在一個執行的 servlet 中。但是序列化會產生許多問題,包括類庫版本或 Java 運行時環境方面的問題。新的 XMLEncoder / XMLDecoder 類允許將 JavaBean 組件狀態轉儲到文本文件中以便易於在 Java 程序外部進行修改,或者更有可能的是為了生成這種文件。讓我們看一下如何使用這兩個類以及如何分析生成的文件。
開始
開始時,我們需要定義一個我們要初始化、保存和重新創建的類。讓我們定義一個帶有以下 4 個屬性的類:
測試分數的整數數組,可當做一個經過索引的屬性
只讀 float 屬性,表示平均分數
String 屬性,代表學生的姓名
java.awt.Point 屬性,代表學生在班裡的座位
這個可變的屬性類型集將演示編碼器如何處理不同的數據類型。 清單 1 顯示樣本類定義。(它也在 net.zukowski.ibm 包中。請參閱 參考資料,下載本文中使用的代碼。)那兒甚至有一個有用的 toString() 方法,我們可以使用這個方法直觀地看到檢索出的值是設置正確的。
保存狀態
既然我們有了用於保存的類,我們可創建一個實例並使用 XMLEncoder 進行保存。這個類可以在 java.beans 包中被找到,它的工作原理與 ObjectOutputStream 相同,但不是 OutputStream 類層次結構的一部分。您可以將要保存到的輸出流對象傳入 OutputStream ,並調用其 writeObject() 方法將對象寫入到流中。這很簡單。
清單 2. 創建一個實例並將其保存為 XML // Create
Sample sample = new Sample();
sample.setScores(new int[] {100, 90, 75});
sample.setName("Gore");
sample.setSeat(new Point(5, 3));
// Save
XMLEncoder encoder = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream("Sample.xml")));
encoder.writeObject(sample);
encoder.close();
檢查格式
當檢查清單 3 所示的 XML 文件時,您會注意到如何讀取格式是與輸出在一起編碼的,在本例中是與 v1.4 beta 中的 XMLDecoder 一起編碼的。這種方法使得將來的發行版能夠更改格式,這樣如果使用的是比較舊的 XML 文件,新的解碼器在生成 XML 文件時會知道使用的是哪種編碼類型。從本質上來說,這個文件是一個正規 XML 文件,服從特定的 DTD(本文中沒有引用到)。但是,解碼器能夠識別該文件。
清單 3. 經過編碼的 XML 樣本實例<?xml version="1.0" encoding="UTF-8"?>
<java version="1.4.0-beta" class="java.beans.XMLDecoder">
<object class="net.zukowski.ibm.Sample">
<void property="name">
<string>Gore</string>
</void>
<void property="scores">
<array class="int" length="3">
<void index="0">
<int>100</int>
</void>
<void index="1">
<int>90</int>
</void>
<void index="2">
<int>75</int>
</void>
</array>
</void>
<void property="seat">
<object class="java.awt.Point">
<int>5</int>
<int>3</int>
</object>
</void>
</object>
</java>
這個特定的 XML 文件未顯示如何嵌入用於復位 bean 屬性的方法調用,如添加偵聽器以及將組件添加到容器。
讀回
讀取原始圖的對象圖就如保存它一樣容易,但這次我們使用 XMLDecoder 。解碼器的工作原理與 ObjectInputStream 相同,使用它可將文件的 InputStream 傳送到構造函數中,並使用 readObject() 方法讀取對象。您仍然必須將結果強制轉換為適當的類型。
清單 4. XML 的讀回 // Read
XMLDecoder decoder = new XMLDecoder(
new BufferedInputStream(
new FileInputStream("Sample.xml")));
Sample sample2 = (Sample)decoder.readObject();
decoder.close();
完整的示例
從本質上來說,這個示例包括了將 JavaBean 組件狀態編碼進 XML 以及從 XML 中解碼出來的全部內容。這個示例在後台進行的工作要比我們看到的多得多。但是,要使用類,您不必了解全部內容,就象進行序列化一樣。如果您對自己生成 XML 文件感興趣,您還必須閱讀更多有關文件格式的內容(請參閱 參考資料)。
這裡是一個創建實例,對其進行編碼,然後對其進行解碼的完整的測試示例。
清單 5. 完整的測試示例import net.zukowski.ibm.Sample;
import java.io.*;
import java.beans.*;
import java.awt.Point;
public class SampleTest {
public static void main (String args[]) throws Exception {
Sample sample = new Sample();
sample.setScores(new int[] {100, 90, 75});
sample.setName("Gore");
sample.setSeat(new Point(5, 3));
XMLEncoder encoder = new XMLEncoder(
new BufferedOutputStream(
new FileOutputStream("Sample.xml")));
encoder.writeObject(sample);
encoder.close();
System.out.println(sample);
XMLDecoder decoder = new XMLDecoder(
new BufferedInputStream(
new FileInputStream("Sample.xml")));
Sample sample2 = (Sample)decoder.readObject();
decoder.close();
System.out.println(sample2);
}
}