Merlin 的魔力: 将 JavaBean 组件状态序列化到 XML

级别: 初级                    John Zukowski                   2001 年 7 月 01 日

     将 JavaBean 组件状态长期持久地保存在 XML 文档中的功能在 J2SE 的 1.4 版本中得到了实现。 Merlin 的魔力系列的这一部分向您展示如何使用新的 XMLEncoderXMLDecoder 类,绕过序列化并且允许您生成完全初始化的 bean 实例。

        Merlin 的这个功能可以将 JavaBean 组件状态长期持久地保存在 XML 文档中。序列化工作适合短期编组的需要(对于 CORBA 和 RMI)或适合将状态信息保存在一个执行的 servlet 中。但是序列化会产生许多问题,包括类库版本或 Java 运行时环境方面的问题。新的 XMLEncoderXMLDecoder 类允许将 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[] {1009075});
  sample.setName(
"Gore");
  sample.setSeat(
new Point(53));
  
// 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[] {1009075});
    sample.setName(
"Gore");
    sample.setSeat(
new Point(53));
    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);
  }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值