Sunday, February 2, 2014

Convert Java Object to XML and XML to Java Object with XStream

Once I got to deal with an incident that loading a very large data (20 MB+)  from the DB and populate as java object (the java object is of many nested / referenced class) and I need to load that every time I start my server. Though we have a distributed cache in place subsequent load would be very fast however the first time load was taking more than 9 minutes.

I was thinking rather loading from DB on server restart if 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 its 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 XSteram library

First, let's create a Sample Object (you can use any existing class as well) as follows

SampleObject.java

 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<String> omitFieldsRegXList) throws IOException {  
         xstreamInitializeSettings(objTobeXMLTranslated, omitFieldsRegXList);  
         toXMLFile(objTobeXMLTranslated, fileName);      
     }      
     /**  
      * @  
      * @param objTobeXMLTranslated  
      */  
     public void xstreamInitializeSettings(Object objTobeXMLTranslated, List<String> omitFieldsRegXList) {  
         if(omitFieldsRegXList != null && omitFieldsRegXList.size() > 0){  
             Iterator<String> 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");  
     }  
 }  
few Test cases to verify

 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 "<com.mysamples.thoughtworks.xstream.SampleObject><name>Test</name><testInt>9</testInt></com.mysamples.thoughtworks.xstream.SampleObject>";  
     }  
     private String getExpectedStringOutOfSampleObject2() {  
         return "<com.mysamples.thoughtworks.xstream.SampleObject><name>Test2</name><testInt>99</testInt></com.mysamples.thoughtworks.xstream.SampleObject>";  
     }      
 }  
Add the following dependency in your pom.xml (dependencies section)
         <dependency>  
             <groupId>com.thoughtworks.xstream</groupId>  
             <artifactId>xstream</artifactId>  
             <version>1.4.5</version>  
         </dependency>  
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.
 <com.mysamples.thoughtworks.xstream.SampleObject>  
  <name>Test2</name>  
  <testInt>99</testInt>  
 </com.mysamples.thoughtworks.xstream.SampleObject>