级别: 初级 John Zukowski 2001 年 7 月 01 日 将 JavaBean 组件状态长期持久地保存在 XML 文档中的功能在 J2SE 的 1.4 版本中得到了实现。 Merlin 的魔力系列的这一部分向您展示如何使用新的 XMLEncoder
和 XMLDecoder
类,绕过序列化并且允许您生成完全初始化的 bean 实例。
Merlin 的这个功能可以将 JavaBean 组件状态长期持久地保存在 XML 文档中。序列化工作适合短期编组的需要(对于 CORBA 和 RMI)或适合将状态信息保存在一个执行的 servlet 中。但是序列化会产生许多问题,包括类库版本或 Java 运行时环境方面的问题。新的 XMLEncoder
/ XMLDecoder
类允许将 JavaBean 组件状态转储到文本文件中以便易于在 Java 程序外部进行修改,或者更有可能的是为了生成这种文件。让我们看一下如何使用这两个类以及如何分析生成的文件。
开始
开始时,我们需要定义一个我们要初始化、保存和重新创建的类。让我们定义一个带有以下 4 个属性的类:
测试分数的整数数组 只读 float
属性,表示平均分数 String
属性,代表学生的姓名 java.awt.Point
属性,代表学生在班里的座位
这个可变的属性类型集将演示编码器如何处理不同的数据类型。
清单1
package net.zukowski.ibm; import java.awt.Point; public class Sample { private int [] scores; private String name; private Point seat; public void setScores( int [] value) ... { scores = value; } public void setScores( int value, int position) ... { scores[position] = value; } public int [] getScores() ... { return scores; } public int getScores( int position) ... { return scores[position]; } public float getAverage() ... { float sum = 0 ; int count = scores.length; float avg; if (count == 0 ) ... { avg = - 1 ; } else ... { for ( int i = 0 ; i < count; i ++ ) ... { sum += scores[i]; } avg = sum / count; } return avg; } public void setName(String value) ... { name = value; } public String getName() ... { return name; } public void setSeat(Point value) ... { seat = value; } public Point getSeat() ... { return seat; } public String toString() ... { return getClass().getName() + " [scores= " + asString(scores) + " ,avg= " + getAverage() + " ,name= " + name + " ,seat= " + seat + " ] " ; } private String asString( int [] array) ... { StringBuffer buffer = new StringBuffer( " [ " ); for ( int i = 0 , n = array.length; i < n; i ++ ) ... { if (i != 0 ) ... { buffer.append( " , " ); } buffer.append(array[i]); } buffer.append(" ] " ); return buffer.toString(); } }
...
有一个有用的 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(); ...
!!!注意:XMLEncoder的writeObject(Object o)方法的参数(o)的类型类必须是public的,否则会报 Class sun.reflect.misc.Trampoline can not access a member of class XXX.XXX.XXX with modifiers "什么什么"
检查格式
当检查清单 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); } }...