Menu

Serializing Java Objects with XStream

August 18, 2004

Michael Fitzgerald

Joe Walnes's XStream is a unique open-source Java library for serializing objects into XML and deserializing that XML into objects. Unlike other APIs, such as David Megginson's XMLWriter or Elliotte Rusty Harold's XOM, which use specific classes and methods to produce XML, XStream relies on Java idioms such as object names to produce element names and strings within classes to produce element content. It also produces a kind of reflection of objects in XML.

XStream is being actively developed by a small project team with over a dozen contributors. It promises to become a very useful tool for persistence and transport; and I think it embraces, as does Joe Walnes, some virtues of agile programming.

Joe Walnes explained the following in private correspondence:

XStream's primary purpose is for serialization. It allows existing Java objects to be converted to clean XML and then restored again, without modifications. This is particularly useful as a form of persistence (no complicated database mappings required) or for sending objects over the wire. It has been optimized for this and is in heavy use on production systems.

XStream offers a two-minute tutorial and JavaDocs. Unfortunately, the XStream distribution doesn't yet provide example programs, though there is a test suite. This article demonstrates several example Java programs that should help you get started with XStream today.

The current, stable version of XStream is 1.0.1, which was released at the end of May 2004. This article, however, uses the latest snapshot available in late July 2004. Programs were compiled and run with Sun's Java 1.4.2_05 and included an XStream JAR (xstream-SNAPSHOT.jar) in the classpath at compile time. The examples also use Aleksander Slominski's speedy XML Pull Parser or XPP (xpp3-1.1.3.3_min.jar) at runtime. Both the stable and snapshot versions of XStream includes JARs. Download both the XStream archive and the example programs to a working directory.

A Simple Program

Let's start with a simple program that shows the basics of XStream serialization. The program Hello.java follows. It is available in the sample archive for this article. The program uses XStream to output a string in XML:

import com.thoughtworks.xstream.XStream;



public class Hello {

    public static void main(String[] args) {



        XStream xstream = new XStream();



        String salutation = "Hello, World!";



        String xml = xstream.toXML(salutation);



        System.out.print(xml);

    }



}

The public class Hello imports only one class, com.thoughtworks.xstream.XStream. It calls a constructor for XStream, creating the object xstream. Then it uses the toXML method to store the string salutation as XML, and writes the XML to the console using the System.out.print method.

Compile the program using this command line at a shell prompt in the working directory:

javac -classpath .;xstream-SNAPSHOT.jar Hello.java

This shows the current directory and the XStream JAR in the classpath explicitly. (Of course, use colons instead of semicolons if you are on Unix.) Once Hello.java compiles successfully, run it with this line:

java -cp .;xstream-SNAPSHOT.jar;xpp3-1.1.3.3_min.jar Hello

This line adds the XPP JAR to the command line; it should output the following:

<string>Hello, World!</string>

XStream automatically wraps the Java String salutation in the XML element string. The string element appears to be an example of XStream's style of XML reflection. If you really want to see this in action, try Reflect.java:

import com.thoughtworks.xstream.XStream;



public class Reflect {

    public static void main(String[] args) {



        XStream xstream = new XStream();



        String xml = xstream.toXML(xstream);



        System.out.print(xml);

    }

}

This program serializes the object xstream into XML, producing over 7,000 lines of "reflection." If you want to avoid the dependency on XPP, you can use DOM instead, like this (HelloDom.java):

import com.thoughtworks.xstream.XStream;

import com.thoughtworks.xstream.io.xml.DomDriver;



public class HelloDom {

    public static void main(String[] args) {



        XStream xstream = new XStream(new DomDriver());



        String salutation = "Hello, World!";



        String xml = xstream.toXML(salutation);



        System.out.print(xml);

    }

}

The differences between Hello.java and HelloDom.java are highlighted in bold: HelloDom.java imports the additional class com.thoughtworks.xstream.io.xml.DomDriver and then uses DomDriver in the XStream constructor. When you run HelloDom, you can drop the reference to the XPP JAR on your classpath.

Using Another Class

The next program, Instant.java, uses a non-public outer class, Date, to represent some data for a date:

import com.thoughtworks.xstream.XStream;



class Date {

    int year;

    int month;

    int day;

}



public class Instant {

    public static void main(String[] args) {



        XStream xstream = new XStream();



        Date date = new Date();

        date.year = 2004;

        date.month = 8;

        date.day = 15;



        xstream.alias("date", Date.class);



        String decl = "<?xml version=\"1.0\"?>\n";



        String xml = xstream.toXML(date);



        System.out.print(decl + xml);

    }

}

The class Date holds three fields, all of which are integers. After the Date constructor, each of these fields is given a value, e.g. date.year = 2004;. The alias method creates an alias XML element name for the Date class, changing the default name from Date to date. XStream uses the fully qualified class name for the element name, including the package name, so the alias method will come in handy for tweaking names. The program also creates an XML declaration and uses it in its output.

Compile and run the program, and you will get this output:

<xml version="1.0"?>

<date>

  <year>2004<year>

  <month>8<month>

  <day>15<day>

<date>

Deserializing XML to Objects

The final program, Deserialize.java, shows you how to deserialize XML to an object, and then to reuse it:

import com.thoughtworks.xstream.XStream;



class Date {

    int year = 2004;

    int month = 8;

    int day = 15;

}



public class Deserialize {



    public static void main(String[] args) {



        XStream xstream = new XStream();



        Date date = new Date();



        xstream.alias("date", Date.class);



        String xml = xstream.toXML(date);



        System.out.print(xml);



        Date newdate = (Date)xstream.fromXML(xml);

        newdate.month = 12;

        newdate.day = 2;



        String newxml = xstream.toXML(newdate);



        System.out.print("\n\n" + newxml);

    }

}

Note this line from Deserialize.java:

Date newdate = (Date)xstream.fromXML(xml);

The line creates a new object newdate using the fromXML method to convert the string xml back to an object (also casting it as Date).

After compiling and running Deserialize.java, you will see this output (two XML documents):

<date>

  <year>2004<year>

  <month>8<month>

  <day>15<day>

<date>



<date>

  <year>2004<year>

  <month>12<month>

  <day>2<day>

<date>

The second instance of date comes from the object created from deserialized XML.

Conclusion

This article has introduced you to the basic features and capabilities of XStream. For additional insights, you might have a look at XStream test programs that use maps or collections (from the test suite). There is plenty of CVS activity, enough to give me hope that XStream is in active development and will be around for awhile. I think XStream takes a nifty approach to XML serialization and persistence, and I'll be keeping my eye on it for even more innovation in the future.