XStream

I needed a way to save and recall data easily from within my Java programs. After a little googling I found XStream, which is a package that will encode an entire object into XML:

String xml = xstream.toXML(myObject);

and decode it when you need it:

MyClass newObject = (MyClass)xstream.fromXML(xml);

Wow! I suppose these XML parsers are available in all OOP languages. This is the first time I’ve seen one. I can’t believe how powerful it is. I guess the point is that you just save the state of your whole program in one go. In this blog I’m going to go through a full noob-friendly example of how to get and use XStream.

First download the XStream binaries (this is a zipped bundle of jars) from http://xstream.codehaus.org/download.html. When I did this (Dec 2010) the last stable versions was xstream-distribution-1.3.1-bin.zip. Unzip it, locate the files “xstream-1.3.1.jar” and “xpp3_min-1.1.4c.jar”, and copy them into your project’s directory (in my case this was “~/Desktop/XStreamExample/”).

Next, from the terminal, create yourself a new java file called “myProgram.java” by doing “touch myProgram.java”. Here’s how things look from the terminal at this point:

chas-egans-macbook-pro:XStreamExample chas$ ls myProgram.java xpp3_min-1.1.4c.jar xstream-1.3.1.jar chas-egans-macbook-pro:XStreamExample chas$

Now, put this into “myProgram.java” using emacs:

 import com.thoughtworks.xstream.XStream; public class myProgram { public myProgram() { XStream xstream = new XStream(); //Create a person Person chas = new Person("Chas", "Egan"); chas.setPhone("1800-PIZZAMAN"); //Tell me about chas System.out.println("==== Info about chas ===="); chas.printName(); chas.printPhone(); //Encode to XML String xml = xstream.toXML(chas); //Cast a new person from the XML Person chasTwin = (Person)xstream.fromXML(xml); //Tell me about chasTwin System.out.println("==== Info about chasTwin ===="); chasTwin.printName(); chasTwin.printPhone(); //And what did the xml string look like? System.out.println("==== The coded xml ===="); System.out.println(xml); } public static void main(String[] args) { new myProgram(); } private class Person { private String firstName; private String lastName; private PhoneNumber homeNumber; public Person(String fn, String ln){ firstName = fn; lastName = ln; } public void printName(){ System.out.println("Name: " + firstName + " " + lastName); } public void printPhone(){ System.out.println("Phone: " + getPhone()); } public void setPhone(String num){ homeNumber = new PhoneNumber(num); } public String getPhone(){ return homeNumber.getNumber(); } } private class PhoneNumber { private String number; public PhoneNumber(String s) { setNumber(s); } public void setNumber(String s) { number = s; } public String getNumber() { return number; } } }

Compile it from the terminal by typing

javac -classpath .:xstream-1.3.1.jar myProgram.java

Then run it by typing

java -cp .:xstream-1.3.1.jar:xpp3_min-1.1.4c.jar myProgram

You should get the following output.

==== Info about chas ==== Name: Chas Egan Phone: 1800-PIZZAMAN ==== Info about chasTwin ==== Name: Chas Egan Phone: 1800-PIZZAMAN ==== The coded xml ==== <myProgram_-Person> <firstName>Chas</firstName> <lastName>Egan</lastName> <homeNumber> <number>1800-PIZZAMAN</number> <outer-class/> </homeNumber> <outer-class reference="../homeNumber/outer-class"/> </myProgram_-Person>

If so, then great… it works! By the way, if you want to know how I display xml/html tags on a website, I used the converter here. But what exactly does our “myProgram” program do?

It defines a class called a “Person”, which has a first name, a last name, and a telephone number. It creates one instance of the class called “chas” and gives it the appropriate properties. Then “chas” is parsed into a String called “xml” using the xstream parser. Later we create a new “person” called “chasTwin” by decoding the “xml” string using xstream. The printed output shows that “chas” and “chasTwin” are identical. It also shows the raw XML, which is surprisingly concise.

To get it working there were 4 key steps. These were

  1. Import the XStream package (the first line in “myProgram.java”; highlighed in red) so the compiler knows what you mean by “XStream”.
  2. Create an object of the XStream class (which I called xstream).
  3. Make sure you include the XStream jar in the classpath when you compile (refer compilation command above).
  4. Make sure you include both the XStream jar, and the xpp3 jar in the classpath when you run (refer run command above).

Edit: I just thought I’d extend the example to do a full XML file output & XML file read (above we wrote and read from a String). All we have to do is create input file and output file streams and use those in place of the String variable we were using above. The new lines are coloured magenta.

import com.thoughtworks.xstream.XStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; public class myProgram { public myProgram() { XStream xstream = new XStream(); //Create a person Person chas = new Person("Chas", "Egan"); chas.setPhone("1800-PIZZAMAN"); //Tell me about chas System.out.println("==== Info about chas ===="); chas.printName(); chas.printPhone(); //Encode to XML file try { FileOutputStream fs = new FileOutputStream("saved_person.xml"); xstream.toXML(chas, fs); } catch (FileNotFoundException e1) { e1.printStackTrace(); } //Cast a new person from the XML file Person chasTwin = new Person("", ""); try { FileInputStream fis = new FileInputStream("saved_person.xml"); xstream.fromXML(fis, chasTwin); } catch (FileNotFoundException e1) { e1.printStackTrace(); } //Tell me about chasTwin System.out.println("==== Info about chasTwin ===="); chasTwin.printName(); chasTwin.printPhone(); } public static void main(String[] args) { new myProgram(); } private class Person { private String firstName; private String lastName; private PhoneNumber homeNumber; public Person(String fn, String ln){ firstName = fn; lastName = ln; } public void printName(){ System.out.println("Name: " + firstName + " " + lastName); } public void printPhone(){ System.out.println("Phone: " + getPhone()); } public void setPhone(String num){ homeNumber = new PhoneNumber(num); } public String getPhone(){ return homeNumber.getNumber(); } } private class PhoneNumber { private String number; public PhoneNumber(String s) { setNumber(s); } public void setNumber(String s) { number = s; } public String getNumber() { return number; } } }

“Gravity means your spit is always going to go down.” – Bear Grylls