View Source

We demonstrate usage of this tool with a simple tutorial. Assume a _Task_ class below with a _prioritized_ field indicating whether it is a prioritized task:
{code}
package example;

public class Task {
public boolean prioritized;
}
{code}
With XStream, we can serialize object of this class to XML like below:
{code}
import com.thoughtworks.xstream.XStream;

public class Test {
public static void main(String args[]) {
Task task = new Task();
task.prioritized = true;
String xml = new XStream().toXML(task);
saveXmlToFileOrDatabase(xml);
}
}
{code}
The resulting XML will be:
{code}
<example.Task>
<prioritized>true</prioritized>
</example.Task>
{code}
And you can deserialize the XML to get back task object:
{code}
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class Test {
public static void main(String args[]) {
String xml = readXmlFromFileOrDatabase();
Task task = (Task)(new XStream(new DomDriver()).fromXML(xml));
}
}
{code}
Everything is fine. Now we find a prioritized flag is not enough, so we enhance the Task class to use a numeric priority field ranging from 1 to 10:
{code}
package example;

public class Task {
public int priority;
}
{code}
However deserialization of previously saved xml is no longer possible since the new Task class is not compatible with previous version. XMT comes to rescue: it introduces class _VersionedDocument_ to version serialized XMLs and handles the migration. With XMT, serialization of task object can be written as:
{code}
package example;
import com.pmease.commons.xmt.VersionedDocument;

public class Test {
public static void main(String args[]) {
Task task = new Task();
task.prioritized = true;
String xml = VersionedDocument.fromBean(task).toXML();
saveXmlToFileOrDatabase(xml);
}
}
{code}
The resulting XML will be:
{code}
<?xml version="1.0" encoding="UTF-8"?>

<example.Task version="0">
<prioritized>true</prioritized>
</example.Task>
{code}
Compared with the XML generated by directly using XStream, an additional attribute _version_ is added to the root element indicating version of associated class. The value is set to _0_ unless there are migration methods defined in the class as we will introduce below.

When Task class is evolved to use numeric priority field, we add a migrate method like below:
{code}
package com.pmease.commons.xmt.bean;

import java.util.List;
import org.dom4j.Element;
import com.pmease.commons.xmt.VersionedDocument;

public class Task {
private int priority;

public int getPriority() {
return priority;
}

public void setPriority(int priority) {
this.priority = priority;
}

@SuppressWarnings("unused")
private void migrate1(VersionedDocument dom, List<String> versions) {
Element element = dom.getRootElement().element("prioritized");
element.setName("priority");
if (element.getText().equals("true"))
element.setText("10");
else
element.setText("1");
}
}
{code}
Here method _migrate1_ migrates the XML from version 0 to 1. The XML to be migrated is passed as a _VersionedDocument_ object which implements dom4j _Document_ interface and you may use dom4j to migrate it to be compatible with current version of the class. The _versions_ parameter is used to handle the migration if class inheritance hierarchy is changed and will be introduced in [class hierarchy migration chapter].
In this migration method, we read back the "prioritized" element of version 0, rename it as "priority", and then set the value as "10" if the task is originally a prioritized task; otherwise, set the value as "0".

With this migration method defined, you can now safely deserialize the task object from XML:
{code}
package example;

import com.pmease.commons.xmt.VersionedDocument;

public class Test {
public static void main(String args[]) {
String xml = readXmlFromFileOrDatabase();
Task task = (Task) VersionedDocument.fromXML(xml).toBean();
}
}
{code}