Sunday, July 31, 2011

Sample JAXB Application Converting POJO to XML Element and Vice-versa

In developing SOA applications, it is necessary that you have tools in converting Java objects to XML and vice-versa. In Oracle Human Task Services for example, the task payloads are represented as XML elements, and if there's a need to manipulate those payload then, I believe that its better to do the manipulation on a Java instance equivalent, rather than navigating to the complex tree structure of the XML payload. With the Java instance, you could take advantage of Java's vast frameworks and utilities.


In this post, I will demonstrate how to convert POJO's to XML and vice-versa using Java Architecture for XML Binding (JAXB), and will give some tips in annotating our entities to avoid some common gotchas.

To be able to convert your POJO to XML, it is mandatory that you put an "@XmlRootElement" annotation to your target classes.
package soadev.jaxbsample.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name = "job")
@XmlAccessorType(XmlAccessType.FIELD)
public class Job{
    private String jobId;
    private String jobTitle;
    private Long maxSalary;
    private Long minSalary;
    //getters and setters
The root name "job" above will be the root of the generated XML as follows:
<job>
   <jobId></jobId>
   <jobTitle></jobTitle>
   <maxSalary></maxSalary>
   <minSalary></minSalary>
</job>

The "@XmlAccessorType(XmlAccessType.FIELD)" annotation tells JAXB that only the fields will be marshalled to XML. There are other types which you can read from the links near the end of this post. I am more inclined to use this annotation particularly because our entities persistence annotations are also on the fields, and that we have a lot of transient methods like "computeTotal" which value I don't need to be marshalled.

I will also recommend that you removed any unnecessary associations (some auto-generated by JDeveloper when creating entities from database tables)like for example departmentList in the Employee class (mapped by the manager in Departments). Those associations will add too much complexity especially if you are already starting to expose your EJB session beans as Web Services or as EJB Service. When you cannot remove it due to some usage requirement then put "@XmlTransient" annotation if those associations are not necessary to be marshalled to XML.

If you have fields of type "java.sql.Timestamp", create a TimeStampAdapter class as follows:

package soadev.jaxb.adapters;

import java.sql.Timestamp;
import java.util.Date;
import javax.xml.bind.annotation.adapters.XmlAdapter;

public class TimestampAdapter extends XmlAdapter<Date, Timestamp> {

    public Date marshal(Timestamp value) {
        if(value == null){
            return null;
        }
        return new Date(value.getTime());
    }

    public Timestamp unmarshal(Date value) {
        if (value == null){
            return null;
        }
        return new Timestamp(value.getTime());
    }
}
...and annotate your approriate fields as follows:
    @XmlJavaTypeAdapter(value = TimestampAdapter.class)
    private Timestamp hireDate;
This annotation can also be put inside a "package-info.java". Please see the links for details.

The runner class

The class below shows how to convert POJO to XML. It also contains a sample on how to convert to POJO an XML element with a different root name.

package soadev.jaxbsample.clients;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import oracle.bpel.services.common.util.XMLUtil;

import org.w3c.dom.Document;

import org.w3c.dom.Element;

import soadev.jaxbsample.model.Department;
import soadev.jaxbsample.model.Employee;
import soadev.jaxbsample.model.Job;

public class SimpleJaxbClient {
    public static void main(String[] args) {
        SimpleJaxbClient client = new SimpleJaxbClient();
        try {
            client.testMarshallUnmarshallSimplePojoWithSameRootQName();
            client.testMarshallUnmarshallComplexPojoWithSameRootQName();
            client.testUnmarshallComplexXmlWithDifferentRootQName();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void testMarshallUnmarshallSimplePojoWithSameRootQName() throws Exception {
        System.out.println("----Start testMarshallUnmarshallSimplePojoWithSameRootQName----");
        JAXBContext context = JAXBContext.newInstance(Job.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        System.out.println("Instantiating simple pojo...");
        Job job = new Job();
        job.setJobId("SOADEV");
        job.setJobTitle("SOA Developer");
        job.setMaxSalary(10000L);
        job.setMinSalary(8000L);
        System.out.println("Simple pojo created: " + job);
        System.out.println("Marshalling pojo to a DOM Node...");
        DocumentBuilder docBuilder =
            DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document = docBuilder.newDocument();
        marshaller.marshal(job, document);
        Element jobElement = document.getDocumentElement();
        System.out.println("Job element created: " + jobElement);
        System.out.println(XMLUtil.toString(jobElement));
        System.out.println("Unmarshalling an xml element to a POJO");
        Unmarshaller unmarshaller = context.createUnmarshaller();
        Job jobPojoFromXml = (Job)unmarshaller.unmarshal(jobElement);
        System.out.println("Simple pojo from xml created :" + jobPojoFromXml);
        System.out.println(jobPojoFromXml);
        System.out.println(jobPojoFromXml.getJobTitle());
        System.out.println(jobPojoFromXml.getJobId());
        System.out.println("----End testMarshallUnmarshallSimplePojoWithSameRootQName----");
    }
    
    public void testMarshallUnmarshallComplexPojoWithSameRootQName()throws Exception{
        System.out.println("----Start testMarshallUnmarshallComplexPojoWithSameRootQName----");
        JAXBContext context = JAXBContext.newInstance(Employee.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        System.out.println("Instantiating complex pojo...");
        Employee employee = new Employee();
        employee.setEmployeeId(1L);
        employee.setFirstName("Rommel");
        employee.setLastName("Pino");
        Job job = new Job();
        job.setJobId("SOADEV");
        job.setJobTitle("SOA Developer");
        job.setMaxSalary(10000L);
        job.setMinSalary(5000L);
        employee.setJob(job);
        Department department = new Department();
        department.setDepartmentName("Java Team");
        employee.setDepartment(department);
        System.out.println("Complex pojo created: " + employee);
        System.out.println("Marshalling complex pojo to a DOM Node...");
        DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document = docBuilder.newDocument();
        marshaller.marshal(employee, document);
        Element employeeElement = document.getDocumentElement();
        System.out.println("Employee element created: "+ employeeElement);
        System.out.println(XMLUtil.toString(employeeElement));
        System.out.println("Unmarshalling an xml element to a POJO");
        Unmarshaller unmarshaller = context.createUnmarshaller();
        Employee employeePojoFromXml = (Employee)unmarshaller.unmarshal(employeeElement);
        System.out.println("Complex pojo from xml created :" + employeePojoFromXml);
        System.out.println(employeePojoFromXml);
        System.out.println(employeePojoFromXml.getEmployeeId());
        System.out.println(employeePojoFromXml.getFirstName());
        System.out.println(employeePojoFromXml.getLastName());
        System.out.println(employeePojoFromXml.getJob());
        System.out.println(employeePojoFromXml.getJob().getJobTitle());
        System.out.println(employeePojoFromXml.getDepartment());
        System.out.println(employeePojoFromXml.getDepartment().getDepartmentName());
        System.out.println("----End testMarshallUnmarshallComplexPojoWithSameRootQName----");
    }
    
    public void testUnmarshallComplexXmlWithDifferentRootQName()throws Exception{
        System.out.println("----Start testUnmarshallComplexXmlWithDifferentRootQName----");
        //root is 'employeeVariable' instead of 'employee'
        String xmlString = 
            "<employeeVariable>" + 
            "  <employeeId>1</employeeId>" + 
            "  <firstName>Rommel</firstName>" + 
            "  <lastName>Pino</lastName>" + 
            "  <job>" + 
            "    <jobId>SOADEV</jobId>" + 
            "    <jobTitle>SOA Developer</jobTitle>" + 
            "    <maxSalary>10000</maxSalary>" + 
            "    <minSalary>5000</minSalary>" + 
            "  </job>" + 
            "  <department>" +
            "    <departmentName>Java Team</departmentName>" +
            "  </department>" +         
            "</employeeVariable>";
        InputStream is = new ByteArrayInputStream(xmlString.getBytes());
        DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document document = docBuilder.parse(is);
        Element varElement = document.getDocumentElement();
        JAXBContext context = JAXBContext.newInstance(Employee.class);
        Unmarshaller unmarshaller = context.createUnmarshaller();
        JAXBElement<Employee> employeeJaxbElement = unmarshaller.unmarshal(varElement, Employee.class);
        System.out.println("Element variable is :" + employeeJaxbElement.getName());
        Employee employeePojoFromXml = employeeJaxbElement.getValue();
        System.out.println("Complex pojo from xml created :" + employeePojoFromXml);
        System.out.println(employeePojoFromXml);
        System.out.println(employeePojoFromXml.getEmployeeId());
        System.out.println(employeePojoFromXml.getFirstName());
        System.out.println(employeePojoFromXml.getLastName());
        System.out.println(employeePojoFromXml.getJob());
        System.out.println(employeePojoFromXml.getJob().getJobTitle());
        System.out.println(employeePojoFromXml.getDepartment());
        System.out.println(employeePojoFromXml.getDepartment().getDepartmentName());
        System.out.println("----End testUnmarshallComplexXmlWithDifferentRootQName----");
    }    
}
Run Outpout
C:\Oracle\11g\jdk160_24\bin\javaw.exe -client -classpath ...
----Start testMarshallUnmarshallSimplePojoWithSameRootQName----
Instantiating simple pojo...
Simple pojo created: soadev.jaxbsample.model.Job@a6d51e
Marshalling pojo to a DOM Node...
Job element created: oracle.xml.parser.v2.XMLElement@9f5011
<job>
   <jobId>SOADEV</jobId>
   <jobTitle>SOA Developer</jobTitle>
   <maxSalary>10000</maxSalary>
   <minSalary>8000</minSalary>
</job>

Unmarshalling an xml element to a POJO
Simple pojo from xml created :soadev.jaxbsample.model.Job@c62c8
soadev.jaxbsample.model.Job@c62c8
SOA Developer
SOADEV
----End testMarshallUnmarshallSimplePojoWithSameRootQName----
----Start testMarshallUnmarshallComplexPojoWithSameRootQName----
Instantiating complex pojo...
Complex pojo created: soadev.jaxbsample.model.Employee@76fba0
Marshalling complex pojo to a DOM Node...
Employee element created: oracle.xml.parser.v2.XMLElement@949f69
<employee>
   <department>
      <departmentName>Java Team</departmentName>
   </department>
   <employeeId>1</employeeId>
   <firstName>Rommel</firstName>
   <lastName>Pino</lastName>
   <job>
      <jobId>SOADEV</jobId>
      <jobTitle>SOA Developer</jobTitle>
      <maxSalary>10000</maxSalary>
      <minSalary>5000</minSalary>
   </job>
</employee>

Unmarshalling an xml element to a POJO
Complex pojo from xml created :soadev.jaxbsample.model.Employee@82764b
soadev.jaxbsample.model.Employee@82764b
1
Rommel
Pino
soadev.jaxbsample.model.Job@12452e8
SOA Developer
soadev.jaxbsample.model.Department@1bf3d87
Java Team
----End testMarshallUnmarshallComplexPojoWithSameRootQName----
----Start testUnmarshallComplexXmlWithDifferentRootQName----
Element variable is :employeeVariable
Complex pojo from xml created :soadev.jaxbsample.model.Employee@42552c
soadev.jaxbsample.model.Employee@42552c
1
Rommel
Pino
soadev.jaxbsample.model.Job@e5bbd6
SOA Developer
soadev.jaxbsample.model.Department@8ee016
Java Team
----End testUnmarshallComplexXmlWithDifferentRootQName----
Process exited with exit code 0.

Sample Application

You can get the sample application from here. To run, find the SimpleJaxbClient.java and run.

Relevant links

  • JAXB Architecture
  • No comments:

    Post a Comment