Praveen Singh

Using JaxB/Jackson: POJO < - > XML < - > JSON

Introduction


USING JAXB/JACKSON: POJO < - > XML < - > JSON

By reading the heading of this blog if you still wondering, why we need something like this ?
Then i can assume that you are still working in some old school project.
JEE evolved from the era where we used to pass a java object or a jav.util.List instance to jsp page and create a view accordingly.
Now, it doesn't matter, are you working in some WEB 2.0 project or Web Service based project or working with some mobile device.Client and server are often separated from each other.

XML came first to rescue and allow server and client to communicate via platform independent medium.
XML still holds its position very strongly due to ecosystem build around it.
like XSD, XSLT or XPATH support.
JSON came late but rising very fast.
it's ability to take less memory and get parsed in 10% time of XML, make it a idea choice for low memory and low processing power system like mobile devices.

However, absence of feature like data validation, structure validation, etc still make XML love of masses.

In this article, our agenda is described in this image


i.e. we will try to convert a POJO < - > XML < - > JSON
for POJO < - > XML conversion, i used JaxB, which i believe most famous, most feature rich, most flexible and most easy to use XML binding framework available in Java.
I prefer the annotation way of JAXB in this article.

For POJO < - > JSON converion i used codehaus's jackson library.

How XML and JSON will look like.


Before i start, to chose a decent XML is very necessary.
Silent feature of this xml are.
  1. A root level element.
  2. A mandatory attribute
  3. Many child  element
  4. A repeatable element
  5. A String data type.
  6. A int data type
  7. A float data type.
  8. A Calender/ Date data type.



<employee empid="123">              
    <dob>01/01/2011</dob>           
    <firstname>Praveen</firstname>  
    <lastname>Kumar</lastname>
    <projects>                       
        <project>                   
            <name>project_1</name>
            <rating>7.2</rating>    
        </project>
        <project>
            <name>project_2</name>
            <rating>9.1</rating>
        </project>
    </projects>
</employee>



Now this XML will be translated to JSON which will look like


{
    "dob": "01/01/2011",
    "empId": 123,
    "firstName": "Praveen",
    "lastName": "Kumar",
    "projects": [{
        "name": "project_1",
        "rating": 7.2
    }, {
        "name": "project_2",
        "rating": 9.1
    }]
}


CODE.


Now to handle this XML and JSON, we will  need few basic components
  1. A To level Employee POJO.
  2. A Project POJO.
  3. Code to handle Date/Calender conversion.
So Lets start with the top level POJO : Employee



package com.entity;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;

import com.adaptor.CalendarAdapter;

@XmlRootElement(name = "employee")
@XmlAccessorType(XmlAccessType.FIELD)
public class Employee
{
 @XmlElement(name = "dob")
 @XmlSchemaType(name = "date")
 @XmlJavaTypeAdapter(CalendarAdapter.class)
 public Calendar dob;

 @XmlAttribute(name = "empId", required = true)
 private int empId;

 @XmlElement(name = "firstName", required = true)
 private String firstName;

 @XmlElement(name = "lastName")
 private String lastName;

 @XmlElementWrapper(name = "projects")
 private List project = new ArrayList();

 public Employee()
 {
  super();
 }

 public Employee(int empId, String firstName)
 {
  super();
  this.empId = empId;
  this.firstName = firstName;
 }

 public boolean add(Project e)
 {
  return project.add(e);
 }

 public Calendar getdob()
 {
  return dob;
 }

 public int getEmpId()
 {
  return empId;
 }

 public String getFirstName()
 {
  return firstName;
 }

 public String getLastName()
 {
  return lastName;
 }

 public List getProject()
 {
  return project;
 }

 public void setDob(Calendar dob)
 {
  this.dob = dob;
 }

 public void setEmpId(int empId)
 {
  this.empId = empId;
 }

 public void setFirstName(String firstName)
 {
  this.firstName = firstName;
 }

 public void setLastName(String lastName)
 {
  this.lastName = lastName;
 }

 public void setProject(List project)
 {
  this.project = project;
 }

 @Override
 public String toString()
 {
  return "Employee [dob=" + dob.getTime() + ", empId=" + empId
   + ", firstName=" + firstName + ", lastName=" + lastName
   + ", projects=" + project + "]";
 }

}


Coming to next POJO : Project

package com.entity;

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

@XmlRootElement(name = "project")
@XmlAccessorType(XmlAccessType.NONE)
public class Project
{
 @XmlElement(name = "name")
 private String name;

 @XmlElement(name = "rating")
 private float rating;

 public Project()
 {
  super();
 }

 public Project(String name, float rating)
 {
  super();
  this.name = name;
  this.rating = rating;
 }

 public String getName()
 {
  return name;
 }

 public float getRating()
 {
  return rating;
 }

 public void setName(String name)
 {
  this.name = name;
 }

 public void setRating(float rating)
 {
  this.rating = rating;
 }

 @Override
 public String toString()
 {
  return "Project [name=" + name + ", rating=" + rating + "]";
 }

}



Now, As i mentioned already, we will need custom code to convert and format Calender Object.


CalendarAdapter

package com.adaptor;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Calendar;

import javax.xml.bind.annotation.adapters.XmlAdapter;

public class CalendarAdapter extends XmlAdapter
{

 DateFormat df = new SimpleDateFormat("dd/MM/yyyy");

 public Calendar unmarshal(String date) throws Exception
 {
  Calendar calendar = Calendar.getInstance();
  calendar.setTime(df.parse(date));
  return calendar;
 }

 public String marshal(Calendar calendar) throws Exception
 {
  return df.format(calendar.getTime());
 }
}



Now coming to final portion of code, the class which will handle all the stuff

TestJaxB

package com.test;

import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import java.util.Calendar;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

import org.codehaus.jackson.JsonParseException;
import org.codehaus.jackson.map.AnnotationIntrospector;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.xc.JaxbAnnotationIntrospector;

import com.entity.Employee;
import com.entity.Project;

public class TestJaxB
{

 private String pojoToXml(Employee employee) throws JAXBException
 {
  JAXBContext context = JAXBContext.newInstance(Employee.class);
  Marshaller marshaller = context.createMarshaller();
  marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
  StringWriter writer = new StringWriter();
  marshaller.marshal(employee, writer);
  String xmlData = writer.toString();
  return xmlData;
 }

 private Employee xmlToPojo(String xmlData) throws JAXBException
 {
  JAXBContext context = JAXBContext.newInstance(Employee.class);
  StringReader reader = new StringReader(xmlData);
  Unmarshaller unmarshaller = context.createUnmarshaller();
  Employee employee = (Employee) unmarshaller.unmarshal(reader);
  return employee;
 }

 private String pojoToJson(Employee employee) throws JAXBException,
 JsonParseException, JsonMappingException, IOException
 {
  ObjectMapper mapper = new ObjectMapper();
  AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
  mapper.getSerializationConfig().setAnnotationIntrospector(introspector);
  String jsonData = mapper.writeValueAsString(employee);
  return jsonData;
 }

 private Employee jsonToPojo(String jsonData) throws JAXBException,
 JsonParseException, JsonMappingException, IOException
 {
  ObjectMapper mapper = new ObjectMapper();
  AnnotationIntrospector introspector = new JaxbAnnotationIntrospector();
  mapper.getDeserializationConfig().setAnnotationIntrospector(
   introspector);
  Employee employee = mapper.readValue(jsonData, Employee.class);
  return employee;
 }

 public static void main(String[] args) throws JAXBException,
 JsonParseException, JsonMappingException, IOException
 {

  Project project1 = new Project("project_1", (float) 7.2);
  Project project2 = new Project("project_2", (float) 9.1);

  Employee employee = new Employee(123, "Praveen");
  employee.setLastName("Kumar");
  Calendar dob = Calendar.getInstance();
  dob.set(2011, Calendar.JANUARY, 1);
  employee.setDob(dob);
  employee.add(project1);
  employee.add(project2);

  TestJaxB testJaxB = new TestJaxB();

  String xmlData = testJaxB.pojoToXml(employee);
  System.out.println(xmlData);
  employee = (Employee) testJaxB.xmlToPojo(xmlData);
  System.out.println(employee);
  String jsonData = testJaxB.pojoToJson(employee);
  System.out.println(jsonData);
  employee = (Employee) testJaxB.jsonToPojo(jsonData);
  System.out.println(employee);

  System.out.println("MISSSION PASS : "
   + xmlData.equals(testJaxB.pojoToXml(employee)));

 }
}




I hope, this article will help you in converting these three Data Format.
As always your suggestion and query is fully welcomed.

2 comments:

  1. Hi im trying to use xmltypeadapter for calendars but it doesnt seem to be working, i have both jackson and jaxb introspection annotations defined:

    AnnotationIntrospector primary = new JacksonAnnotationIntrospector();
    AnnotationIntrospector secondary = new JaxbAnnotationIntrospector();
    AnnotationIntrospector pair = new AnnotationIntrospector.Pair(primaryIntrospector, secondaryIntropsector);

    but it seems the property still gets converted as an integer in json. Does the property have to be public?

    ReplyDelete
  2. Hi Praveen,

    All your blogs are really helpful.. keep up the good work :)

    ReplyDelete