Skip to main content

skip to main content

developerWorks  >  Java technology  >

Magic with Merlin: Long-term persistence

Serialize JavaBean component state to XML

developerWorks
Document options

Document options requiring JavaScript are not displayed

Discuss

Sample code


Rate this page

Help us improve this content


Level: Introductory

John Zukowski (jaz@zukowski.net), President, JZ Ventures, Inc.

01 Jul 2001

The ability to save the JavaBean component state for long-term persistence within an XML document has been a topic of much discussion with Java developers in the past few years. This feature has finally been adopted in the 1.4 version of J2SE. In this installment of Magic with Merlin, John Zukowski shows you how to use the new XMLEncoder and XMLDecoder classes, bypassing serialization and allowing you to generate fully initialized bean instances.

One new feature of Merlin has been thrown around in various incarnations at Sun's Swing Connection for some time now; in fact, it was first discussed at the 1999 JavaOne show. That feature is the ability to save the JavaBean component state for long-term persistence within an XML document. Serialization works fine for short-term marshaling needs, with CORBA and RMI, or for saving state information within an executing servlet. However, serialization can run into problems across versions of class libraries or Java run-time environments, among many other issues. The new XMLEncoder / XMLDecoder classes permit the dumping of the JavaBean component state to a text file for easy modification outside of a Java program or more likely for the generation of such files. Let's take a look at how to use the classes and examine the file generated.

Getting started

To get started, we need to define a class that we're going to initialize, save, and re-create. Let's define a class with four properties:

  • An integer array of test scores, treated as an indexed property
  • A read-only float property for the score average
  • A String property representing the student's name
  • A java.awt.Point property representing where the student sits in the class

This varied set of property types will demonstrate how the encoder deals with different datatypes. Listing 1 shows the sample class definition. (It's also in package net.zukowski.ibm. Click Sample code at the top of this page (or see Download) to download the article source.) There's even a nice little toString() method that we can use to visually see that the retrieved values are set properly.



Back to top


Saving state

Now that we have a class to save, we can create an instance and use the XMLEncoder to save it. Found in the java.beans package, the class works like an ObjectOutputStream but isn't part of the OutputStream class hierarchy. You pass in the OutputStream you want to save to, and call its writeObject() method to write an object to the stream. It's that easy.

  // 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();



Back to top


Examining the format

As you examine the XML file shown in Listing 3, you'll notice that how to read the format is encoded with the output, in this case with the XMLDecoder from the v1.4 beta. This approach provides for future releases to change the format such that if an older XML file comes around, the new decoder will know what encoding style was used when the XML file was generated. Essentially, the file is a regular XML file, following a particular DTD that is not referenced by the file. Instead, the decoder knows it.

<?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>

Not shown with this particular XML file is how to embed method calls for resetting bean properties, like adding listeners and adding components into containers.



Back to top


Reading back

Reading the object graph of the original graph is as easy as saving it, but this time we use XMLDecoder. The decoder works like the ObjectInputStream, where you pass the InputStream of the file into the constructor, and read the object with the readObject() method. You still even have to cast the results to the proper type.

  // Read
  XMLDecoder decoder = new XMLDecoder(
    new BufferedInputStream(
      new FileInputStream("Sample.xml")));
  Sample sample2 = (Sample)decoder.readObject();
  decoder.close();



Back to top


Complete example

Essentially, that's all there is to encoding and decoding a JavaBean component state to and from XML. There's much more going on behind the scenes here than meets the eye. However, to use the classes, you don't need to know it all, just like with serialization. If you are interested in generating the XML file yourself, you will have to read more about the file format (see Resources).

Here's the complete testing example to create an instance, encode it, and then decode it back.

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);
  }
}




Back to top


Download

NameSizeDownload method
j-mer0731source.zip2 KBHTTP
Information about download methods


Resources



About the author

Author photo

John Zukowski conducts strategic Java consulting with JZ Ventures, Inc. and serves as the resident guru for a number of jGuru's community-driven Java FAQs. His latest books are Java Collections and Definitive Guide to Swing for Java 2 (2nd ed) from Apress. Contact John at jaz@zukowski.net.




Rate this page


Please take a moment to complete this form to help us better serve you.



 


 


Not
useful
Extremely
useful
 


Share this....

digg Digg this story del.icio.us del.icio.us Slashdot Slashdot it!



Back to top