changes.
| 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; |
| |
| | Task task = new Task(); |
| task.prioritized = true; |
| String xml = new XStream().toXML(task); |
| saveXmlToFileOrDatabase(xml); |
| | 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; |
| |
| | String xml = readXmlFromFileOrDatabase(); |
| Task task = (Task)(new XStream(new DomDriver()).fromXML(xml)); |
| | 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; |
| |
| | Task task = new Task(); |
| task.prioritized = true; |
| String xml = VersionedDocument.fromBean(task).toXML(); |
| saveXmlToFileOrDatabase(xml); |
| | 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} |