changes.
| Continue with version "0" of the Task class defined in [Getting Started] chapter: |
| {code} |
| package example; |
| |
| public class Task { |
| public boolean prioritized; |
| } |
| {code} |
| Now we have class _CompileTask_ subclassing from Task class as below: |
| {code} |
| package example; |
| |
| import java.util.List; |
| |
| public class CompileTask extends Task { |
| public List<String> srcFiles; |
| } |
| {code} |
| Instance of _CompileTask_ can be serialized to XML with XMT as below: |
| {code} |
| package example; |
| |
| import java.util.ArrayList; |
| |
| import com.pmease.commons.xmt.VersionedDocument; |
| |
| public class Test { |
| public static void main(String args[]) { |
| CompileTask task = new CompileTask(); |
| task.prioritized = true; |
| task.srcFiles = new ArrayList<String>(); |
| task.srcFiles.add("Class1.java"); |
| task.srcFiles.add("Class2.java"); |
| String xml = VersionedDocument.fromBean(task).toXML(); |
| writeXMLToFileOrDatabase(xml); |
| } |
| } |
| {code} |
| The resulting XML will be: |
| {code} |
| <example.CompileTask version="0.0"> |
| <prioritized>true</prioritized> |
| <srcFiles> |
| <string>Class1.java</string> |
| <string>Class2.java</string> |
| </srcFiles> |
| </example.CompileTask> |
| {code} |
| Pay attention to version attribute of the root element: XMT examines the class hierarchy (except for class _java.lang.Object_) to get current version of each class, and concatenates them with period. Since there are no migrate methods defined in class _Task_ and _CompileTask_, current version of both classes are of "0", and the resulting version of the hierarchy (or composite version) will be "0.0". |
| When deserializing the compile task object from XML, XMT splits this composite version to get XML version for each class in the hierarchy, and repeats the process described in [getting started] chapter for each of these classes. So if class _Task_ is evolved to take numeric priority value described in [getting started] chapter, we simply add migrate methods in _Task_ class, while keep _CompileTask_ class intacted. If we continue to evolve class _CompileTask_ to include a compile option field, and make sure that compile tasks of old version automatically take the default compile option of "-debug", we can then define the migrate method in _CompileTask_ like below, and keep class _Task_ intacted: |
| {code} |
| package example; |
| |
| import java.util.List; |
| |
| public class CompileTask extends Task { |
| public List<String> srcFiles; |
| |
| public String options = "-debug"; |
| |
| @SuppressWarnings("unused") |
| private void migrate1(VersionedDocument dom, List<String> versions) { |
| dom.getRootElement().addElement("options").setText("-debug"); |
| } |
| } |
| {code} |
| This separation of concerns has the benefit of not requiring you to define migrate methods in various sub classes if super class is evolved, and vice versa. |
| |
| Till now, we remains the class hierarchy when we evolve class _Task_ and _CompileTask_. Now let's assume that class _Task_ is removed and class _CompileTask_ needs to take care of the priority field: |
| {code} |
| package example; |
| |
| import java.util.List; |
| import com.pmease.commons.xmt.VersionedDocument; |
| import com.pmease.commons.xmt.MigrationHelper; |
| |
| public class CompileTask { |
| public int priority; |
| |
| public List<String> srcFiles; |
| |
| public String options = "-debug"; |
| |
| @SuppressWarnings("unused") |
| private void migrate1(VersionedDocument dom, List<String> versions) { |
| dom.getRootElement().addElement("options").setText("-debug"); |
| } |
| |
| @SuppressWarnings("unused") |
| private void migrate2(VersionedDocument dom, List<String> versions) { |
| String taskVersion = versions.remove(0); |
| MigrationHelper.migrate(taskVersion, Task.class, dom); |
| } |
| |
| private static class Task { |
| |
| | @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("HIGH"); |
| else |
| element.setText("LOW"); |
| } |
| |
| } |
| } |
| {code} |