- Convert Java Objects to XML and XML to Java Objects with XStream
- Two Minute Tutorial
- Create classes to be serialized
- Initializing XStream
- Serializing an object to XML
- Deserializing an object back from XML
- Summary
- Software
- Xstream java from xml
- Converters
- Object graphs
- Thread safety
- Implicit collections
- Nested Class Summary
Convert Java Objects to XML and XML to Java Objects with XStream
Join the DZone community and get the full member experience.
Once I got to deal with an incident where I had to load a lot of data (20 MB+) from the DB and populate it as java object (the java object is of many nested / referenced classes), and I needed to load that every time I started my server. Though we have a distributed cache in place, subsequent loads would be very fast. However, the first time load was taking more than 9 minutes.
I was thinking that rather than loading from the DB on server restart, I could load from the local file!! (as the data in the db updates less often) that’s where I got to learn about the XStream Library, and it’s so simple that I could convert any java object to XML and back.
Here I will show you how easy it is to use the XStream library
First let’s create a Sample Object (you can use any existing class as well) as follows
public class SampleObject < private String name="Test"; private int testInt ; public String getName() < return name; >public void setName(String name) < this.name = name; >public int getTestInt() < return testInt; >public void setTestInt(int testInt) < this.testInt = testInt; >>
and a helper class for conversion XStreamTranslator.java
import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.Iterator; import java.util.List; import com.thoughtworks.xstream.XStream; public final class XStreamTranslator < private XStream xstream = null; private XStreamTranslator()< xstream = new XStream(); xstream.ignoreUnknownElements(); >/** * Convert a any given Object to a XML String * @param object * @return */ public String toXMLString(Object object) < return xstream.toXML(object); >/** * Convert given XML to an Object * @param xml * @return */ public Object toObject(String xml) < return (Object) xstream.fromXML(xml); >/** * return this class instance * @return */ public static XStreamTranslator getInstance() < return new XStreamTranslator(); >/** * convert to Object from given File * @param xmlFile * @return * @throws IOException */ public Object toObject(File xmlFile) throws IOException < return xstream.fromXML(new FileReader(xmlFile)); >/** * create XML file from the given object with custom file name * @param fileName * @param file * @throws IOException */ public void toXMLFile(Object objTobeXMLTranslated, String fileName ) throws IOException < FileWriter writer = new FileWriter(fileName); xstream.toXML(objTobeXMLTranslated, writer); writer.close(); >public void toXMLFile(Object objTobeXMLTranslated, String fileName, List omitFieldsRegXList) throws IOException < xstreamInitializeSettings(objTobeXMLTranslated, omitFieldsRegXList); toXMLFile(objTobeXMLTranslated, fileName); >/** * @ * @param objTobeXMLTranslated */ public void xstreamInitializeSettings(Object objTobeXMLTranslated, List omitFieldsRegXList) < if(omitFieldsRegXList != null && omitFieldsRegXList.size() >0) < Iterator itr = omitFieldsRegXList.iterator(); while(itr.hasNext())< String omitEx = itr.next(); xstream.omitField(objTobeXMLTranslated.getClass(), omitEx); >> > /** * create XML file from the given object, file name is generated automatically (class name) * @param objTobeXMLTranslated * @throws IOException * @throws XStreamTranslateException */ public void toXMLFile(Object objTobeXMLTranslated) throws IOException < toXMLFile(objTobeXMLTranslated,objTobeXMLTranslated.getClass().getName()+".xml"); >>
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; public class XStreamTranslatorTest < SampleObject sampleObj; XStreamTranslator xStreamTranslatorInst; /** * @throws java.lang.Exception */ @Before public void setUp() throws Exception < sampleObj = new SampleObject(); xStreamTranslatorInst = XStreamTranslator.getInstance(); >/** * @throws java.lang.Exception */ @After public void tearDown() throws Exception < >@Test public void simpleObjectToXMLStringNotNullTest() < String xml = xStreamTranslatorInst.toXMLString(sampleObj); assertNotNull(xml); >@Test public void simpleObjectToXMLStringVerifyTest() < sampleObj.setName("Test"); assertEquals("Test",sampleObj.getName()); sampleObj.setTestInt(9); assertEquals(9,sampleObj.getTestInt()); String xml = xStreamTranslatorInst.toXMLString(sampleObj); String expected = getExpectedStringOutOfSampleObject(); assertEquals(expected, xml.replaceAll("[\\n\\s\\t]+", "")); >@Test public void xmlToObjectVerifyTest() < String xml = getExpectedStringOutOfSampleObject(); SampleObject sampleObj = (SampleObject) xStreamTranslatorInst.toObject(xml); assertNotNull(sampleObj); >@Test (expected=IOException.class) public void xmlToAnyObjectFromFileThatNotExists() throws IOException < SampleObject sampleObj = (SampleObject) xStreamTranslatorInst.toObject(new File("C:\\MyHome\\mySampleCodes\\xstream-samples\\src\\test\\resources\\testNoFile.xml")); assertNotNull(sampleObj); assertEquals("somename",sampleObj.getName()); >@Test public void xmlToAnyObjectFromFile() throws IOException < SampleObject sampleObj = (SampleObject) xStreamTranslatorInst.toObject(new File("C:\\MyHome\\mySampleCodes\\xstream-samples\\src\\test\\resources\\testSampleObject.xml")); assertNotNull(sampleObj); assertEquals("Test",sampleObj.getName()); >@Test public void objToXmlFileTestForNotNull() throws IOException < SampleObject sampleObj = new SampleObject(); sampleObj.setName("Test2"); assertEquals("Test2",sampleObj.getName()); sampleObj.setTestInt(99); assertEquals(99,sampleObj.getTestInt()); xStreamTranslatorInst.toXMLFile(sampleObj); File file = new File(sampleObj.getClass().getName()+".xml"); assertTrue(file.exists()); String sample = FileUtils.readFileToString(file); assertNotNull(sample); >@Test public void objToXmlFileCreate() throws IOException < SampleObject sampleObj = new SampleObject(); sampleObj.setName("Test2"); assertEquals("Test2",sampleObj.getName()); sampleObj.setTestInt(99); assertEquals(99,sampleObj.getTestInt()); xStreamTranslatorInst.toXMLFile(sampleObj); File file = new File(sampleObj.getClass().getName()+".xml"); assertTrue(file.exists()); String sample = FileUtils.readFileToString(file); assertNotNull(sample); assertEquals(getExpectedStringOutOfSampleObject2(),sample.replaceAll("[\\n\\s\\t]+", "")); >private String getExpectedStringOutOfSampleObject() < return ""; > private String getExpectedStringOutOfSampleObject2() < return " Test 9 "; > > Test2 99
Add the following dependency in your pom.xml (dependencies section)
com.thoughtworks.xstream xstream 1.4.5
Run your test cases and see for yourself how the xml got generated from the sample object and back to SampleObject.
following is the sample xml that I have..
Two Minute Tutorial
This is a very quick introduction to XStream. Skim read it to get an idea of how simple it is to convert objects to XML and back again. I’m sure you’ll have questions afterwards.
Create classes to be serialized
Here’s a couple of simple classes. XStream can convert instances of these to XML and back again.
public class Person < private String firstname; private String lastname; private PhoneNumber phone; private PhoneNumber fax; // . constructors and methods >public class PhoneNumber < private int code; private String number; // . constructors and methods >
Note: Notice that the fields are private. XStream doesn’t care about the visibility of the fields. No getters or setters are needed. Also, XStream does not limit you to having a default constructor.
Initializing XStream
To use XStream, simply instantiate the XStream class:
XStream xstream = new XStream();
You require xstream-[version].jar , xpp3-[version].jar and xmlpull-[version].jar in the classpath. Xpp3 is a very fast XML pull-parser implementation. If you do not want to include these dependencies, you can use a standard JAXP DOM parser or since Java 6 the integrated StAX parser instead:
XStream xstream = new XStream(new DomDriver()); // does not require XPP3 library
XStream xstream = new XStream(new StaxDriver()); // does not require XPP3 library starting with Java 6
Note: This class is a simple facade designed for common operations. For more flexibility you may choose to create your own facade that behaves differently.
Now, to make the XML outputted by XStream more concise, you can create aliases for your custom class names to XML element names. This is the only type of mapping required to use XStream and even this is optional.
xstream.alias("person", Person.class); xstream.alias("phonenumber", PhoneNumber.class);
Note: This is an optional step. Without it XStream would work fine, but the XML element names would contain the fully qualified name of each class (including package) which would bulk up the XML a bit. See the Alias Tutorial a more complete introduction.
Serializing an object to XML
Let’s create an instance of Person and populate its fields:
Person joe = new Person("Joe", "Walnes"); joe.setPhone(new PhoneNumber(123, "1234-456")); joe.setFax(new PhoneNumber(123, "9999-999"));
Now, to convert it to XML, all you have to do is make a simple call to XStream:
String xml = xstream.toXML(joe);
The resulting XML looks like this:
Joe Walnes 123
1234-456 123
9999-999
It’s that simple. Look at how clean the XML is.
Deserializing an object back from XML
To reconstruct an object, purely from the XML:
Person newJoe = (Person)xstream.fromXML(xml);
And that’s how simple XStream is!
Note, it is an annoying task to tweak an XStream instance until it can read a given XML format. You will have a much easier job, if you tweak XStream, until it writes the required XML format. NOrmallyt it will then also be able to read it.
Summary
- Create element name to class name aliases for any custom classes using xstream.alias(String elementName, Class cls);
- Convert an object to XML using xstream.toXML(Object obj);
- Convert XML back to an object using xstream.fromXML(String xml);
maybe you like to read the alias tutorial to see more possibilities how you can rename things using XStream. Or look into the condensed overview how to configure XStream to tweak the output.
Software
Xstream java from xml
To create shorter XML, you can specify aliases for classes using the alias() method. For example, you can shorten all occurrences of element
xstream.alias("my-thing", MyThing.class);
Converters
XStream contains a map of Converter instances, each of which acts as a strategy for converting a particular type of class to XML and back again. Out of the box, XStream contains converters for most basic types (String, Date, int, boolean, etc) and collections (Map, List, Set, Properties, etc). For other objects reflection is used to serialize each field recursively. Extra converters can be registered using the registerConverter() method. Some non-standard converters are supplied in the com.thoughtworks.xstream.converters.extended package and you can create your own by implementing the Converter interface. Example
xstream.registerConverter(new SqlTimestampConverter()); xstream.registerConverter(new DynamicProxyConverter());
The converters can be registered with an explicit priority. By default they are registered with XStream.PRIORITY_NORMAL. Converters of same priority will be used in the reverse sequence they have been registered. The default converter, i.e. the converter which will be used if no other registered converter is suitable, can be registered with priority XStream.PRIORITY_VERY_LOW. XStream uses by default the ReflectionConverter as the fallback converter. Example
xstream.registerConverter(new CustomDefaultConverter(), XStream.PRIORITY_VERY_LOW);
Object graphs
XStream has support for object graphs; a deserialized object graph will keep references intact, including circular references. XStream can signify references in XML using either relative/absolute XPath or IDs. The mode can be changed using setMode() :
xstream.setMode(XStream.XPATH_RELATIVE_REFERENCES); | (Default) Uses XPath relative references to signify duplicate references. This produces XML with the least clutter. |
xstream.setMode(XStream.XPATH_ABSOLUTE_REFERENCES); | Uses XPath absolute references to signify duplicate references. This produces XML with the least clutter. |
xstream.setMode(XStream.SINGLE_NODE_XPATH_RELATIVE_REFERENCES); | Uses XPath relative references to signify duplicate references. The XPath expression ensures that a single node only is selected always. |
xstream.setMode(XStream.SINGLE_NODE_XPATH_ABSOLUTE_REFERENCES); | Uses XPath absolute references to signify duplicate references. The XPath expression ensures that a single node only is selected always. |
xstream.setMode(XStream.ID_REFERENCES); | Uses ID references to signify duplicate references. In some scenarios, such as when using hand-written XML, this is easier to work with. |
xstream.setMode(XStream.NO_REFERENCES); | This disables object graph support and treats the object structure like a tree. Duplicate references are treated as two separate objects and circular references cause an exception. This is slightly faster and uses less memory than the other two modes. |
Thread safety
The XStream instance is thread-safe. That is, once the XStream instance has been created and configured, it may be shared across multiple threads allowing objects to be serialized/deserialized concurrently. Note, that this only applies if annotations are not auto-detected on-the-fly.
Implicit collections
To avoid the need for special tags for collections, you can define implicit collections using one of the addImplicitCollection methods.