Sunday, July 28, 2013

Spring OXM

OXM is Spring's Object/XML Mapping support which helps in conversion of Object to XML(Marshalling) and XML to Object(Unmarshalling). For this, spring has two interfaces Marshaller and Unmarshaller defined in spring-oxm under the package org.springframework.oxm.Marshaller . These can be defined as normal beans like other spring beans.
Marshaller and Unmarshaller has one method each for the actions as below.
public interface Marshaller {
    /**
     * Marshals the object graph with the given root into the provided Result.
     */
    void marshal(Object graph, Result result) throws XmlMappingException, IOException;
}
public interface Unmarshaller {
    /**
     * Unmarshals the given provided Source into an object graph.
     */
    Object unmarshal(Source source) throws XmlMappingException, IOException;
}
Implementation:
There are different marshaller instances in spring-oxm. We will go through CastorMashaller because it's easy to implement and configure.
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:schemaLocation="http://www.springframework.org/schema/beans
 http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

 <bean id="converter" class="com.test.spring.oxm.converter.Converter">
  <property name="marshaller" ref="castorMarshaller" />
  <property name="unmarshaller" ref="castorMarshaller" />
 </bean>
 
 <bean id="castorMarshaller" class="org.springframework.oxm.castor.CastorMarshaller">
  <property name="mappingLocation" value="classpath:mapping.xml" />
 </bean>
</beans>
CastorMarshaller is the marshaller and it requires one optional property "mappingLocation" which defines the mapping of class to xml. Sample mapping.xml file is
<?xml version="1.0" encoding="UTF-8"?>
<mapping>
 <class name="com.test.spring.oxm.entity.Employee">
  <map-to xml="employee" />
  <field name="empid" type="integer">
   <bind-xml name="id" node="element" />
  </field>
  <field name="name" type="string">
   <bind-xml name="ename" node="element" />
  </field>
   <field name="dob" type="date" >
   <bind-xml name="dob" node="element"  />
  </field>
   <field name="salary" type="double">
   <bind-xml name="salary" node="element" />
  </field>
 </class>
</mapping>
Points to be noted
  • property "mappingLocation" is optional. We can create CastorMarshaller without mappingLocation but it takes default values while binding
  • Each class tag defines the Object which to be marshalled/unmarshalled with set of field tags. Each corresponds to XML and object mapping.
  • type on the field indicates the type of the node and is mapped to Java Type.
  • map-to and bind-xml tags defines the elements and attributes in the xml. 
  • node attribute in bind-xml defines whether the field should be attribute or element

Code for bean "converter" is as below. Converter internally calls the marshall and unmarshall methods of CastorMarshaller.
package com.test.spring.oxm.converter;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;

import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;

import org.springframework.oxm.Marshaller;
import org.springframework.oxm.Unmarshaller;

public class Converter
{
    private Marshaller marshaller;
    private Unmarshaller unmarshaller;

    public Marshaller getMarshaller()
    {
        return marshaller;
    }

    public void setMarshaller(Marshaller marshaller)
    {
        this.marshaller = marshaller;
    }

    public Unmarshaller getUnmarshaller()
    {
        return unmarshaller;
    }

    public void setUnmarshaller(Unmarshaller unmarshaller)
    {
        this.unmarshaller = unmarshaller;
    }
    
    public String convertToXml(Object obj,String filepath)
    {
        String finalString = new String();
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(filepath);
            getMarshaller().marshal(obj, new StreamResult(fos));
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally {
            if(fos != null)
            {
                try
                {
                    fos.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return finalString;
    }
    
    public Object convertToObject(String filepath)
    {
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(filepath);
            return getUnmarshaller().unmarshal(new StreamSource(fis));
        } 
        catch (Exception e)
        {
            e.printStackTrace();
        }
        finally {
            if(fis != null)
            {
                try
                {
                    fis.close();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}
The object which to marshalled or unmarshalled is
package com.test.spring.oxm.entity;

import java.util.Date;

public class Employee
{
    private int empid;
    private String name;
    private Date dob;
    private Double salary;

    public int getEmpid()
    {
        return empid;
    }
    public void setEmpid(int empid)
    {
        this.empid = empid;
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
    public Date getDob()
    {
        return dob;
    }
    public void setDob(Date dob)
    {
        this.dob = dob;
    }
    public Double getSalary()
    {
        return salary;
    }
    public void setSalary(Double salary)
    {
        this.salary = salary;
    }
}
Finally, the main program is
package com.test.spring.oxm;

import java.util.Date;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.test.spring.oxm.converter.Converter;
import com.test.spring.oxm.entity.Employee;

public class Application
{
    public static void main(String[] args)
    {
        ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
        Converter converter = (Converter)context.getBean("converter");
        Employee emp = new Employee();
        
        emp.setDob(new Date());
        emp.setEmpid(1234);
        emp.setName("Employee Name");
        emp.setSalary(2500.122);
       
        converter.convertToXml(emp,"cust.xml");
        
        Employee emp2 = (Employee)converter.convertToObject("cust.xml");
        System.out.println("Empid : "+emp2.getEmpid());
        System.out.println("Name  : "+emp2.getName());
        System.out.println("Salary: "+emp2.getSalary());
        System.out.println("DOB   : "+emp2.getDob());
    }
}
The xml file generated out of it is :
<?xml version="1.0" encoding="UTF-8"?>
<employee>
 <id>1234</id>
 <ename>Employee Name</ename>
 <dob>2013-07-28T21:17:29.331+05:30</dob>
 <salary>2500.122</salary>
</employee>