December 5, 2014

The JAXB Binding Process Explained

Today in the developer community, no one can dispute the importance of XML. It has become the backbone of many cutting edge technologies. XML is the core layer for data transport, communication, and configuration management. Most software projects are incomplete without the use of XML. It is a standard language when dealing with data. It allows developers to set standards in defining the information that should appear in a document, and in what sequence. Recently, many advanced technologies/protocols that were built used the simplified format of XML to capture and share information among applications. While this article is not about XML, it will highlight its importance with respect to JAXB (a Java library for communicating XMLs).

There are many way to convert data from XML to object and vise-versa. I am elaborating on one of these ways which is simple, light, and easy to learn and develop. So here we go…

JAXB stands for Java Architecture for XML Binding. It provides a mechanism to marshal Java objects into XML and un-marshal XML into objects. Simply, we can say JAXB provides an API to convert objects into XML and XML into objects.

JAXB 2.0 includes several important improvements to JAXB 1.0:-

  • Support for all W3C XML Schema features. (JAXB 1.0 did not specify bindings for some of the W3C XML Schema features.)
  • Support for binding Java-to-XML, with the addition of the javax.xml.bind.annotation package to control this binding. (JAXB 1.0 specified the mapping of XML Schema-to-Java, but not Java-to-XML Schema.)
  • A significant reduction in the number of generated schema-derived classes.
  • Additional validation capabilities through the JAXP 1.3 validation APIs.
  • Smaller runtime libraries.

A JAXB implementation consists of the following architectural components:

  • Schema compiler: Binds a source schema to a set of schema-derived program elements. The binding is described by an XML-based binding language.
  • Schema generator: Maps a set of existing program elements to a derived schema. The mapping is described by program annotations.
  • Binding runtime framework: Provides unmarshalling (reading) and marshalling (writing) operations for accessing, manipulating, and validating XML content using either schema-derived or existing program elements.

The JAXB Binding Process

The following figure shows what occurs during the JAXB binding process.

Figure: Steps in the JAXB Binding Process

JAXB


Common steps in the JAXB data binding process:

  1. Generate classes: An XML schema is used as input to the JAXB binding compiler to generate JAXB classes based on that schema.
  2. Compile classes: All of the generated classes, source files, and application code must be compiled.
  3. Unmarshal: XML documents written according to the constraints in the source schema are unmarshalled by the JAXB binding framework. Note that JAXB also supports unmarshalling XML data from sources other than files and documents, such as DOM nodes, string buffers, SAX sources, and so forth.
  4. Generate content tree: The unmarshalling process generates a content tree of data objects instantiated from the generated JAXB classes; this content tree represents the structure and content of the source XML documents.
  5. Validate (optional): The unmarshalling process involves validation of the source XML documents before generating the content tree. Note that if you modify the content tree in Step 6, you can also use the JAXB Validate operation to validate the changes before marshalling the content back to an XML document.
  6. Process content: The client application can modify the XML data represented by the Java content tree by using interfaces generated by the binding compiler.
  7. Marshal: The processed content tree is marshalled out to one or more XML output documents. The content may be validated before marshalling

I have used jaxb-api-2.2.jar for all examples.

Example 1: Object to XML (Marshalling)

The following example shows the usage of java.xml.bind.JAXBElement class. To proceed, consider the following Employee class which will be used to have objects for marshalling and unmarshalling purposes:

import javax.xml.bind.annotation.XmlAttribute;

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="Employee")

publicclass Employee{

String name;

intage;

intid;

public String getName(){

returnname;

}

@XmlElement(name="name")

publicvoid setName(String name){

this.name = name;

}

publicint getAge(){

returnage;

}

@XmlElement(name = "age")

publicvoid setAge(int age){

this.age = age;

}

publicint getId(){

returnid;

}

@XmlAttribute(name="id")

publicvoid setId(int id){

this.id = id;

}

}

o   @XmlRootElement: specifies the root element for the xml document.

o   @XmlAttribute: specifies the attribute for the root element.

o   @XmlElement: specifies the sub element for the root element.

Now we will create the main class which will be used to marshal, i.e. Convert Employee object to XML. Here we will create a JAXBElement of an Employee object and then update StringWriter object using JAXBContext. This example marshals the Employee object and prints the XML.

import java.io.StringWriter;

import javax.xml.bind.JAXBContext;

import javax.xml.bind.JAXBElement;

import javax.xml.bind.JAXBException;

import javax.xml.namespace.QName;

public class JAXBElementDemo {

public static void main(String[] args) {

//Create an employee object

Employee employee = new Employee();

//fill details of the employee

employee.setName("Prabhat");

employee.setId(1);

employee.setAge(12);

try {

//create JAXBElement of type Employee

//Pass it the employee object

JAXBElement<Employee> jaxbElement = new JAXBElement(

new QName(Employee.class.getSimpleName()),Employee.class, employee);

//Create a String writer object which will be

//used to write jaxbElment XML to string

StringWriter writer = new StringWriter();

// create JAXBContext which will be used to update writer

JAXBContext context = JAXBContext.newInstance(Employee.class);

// marshall or convert jaxbElement containing employee to xml format

context.createMarshaller().marshal(jaxbElement, writer /*new FileOutputStream("employee.xml")*/);

//print XML string representation of Employee object

System.out.println( writer.toString() );

} catch (JAXBException e) {

e.printStackTrace();

}

}

}
  • JAXBContext: class provides the client’s entry point to the JAXB API.
  • JAXBElement: class is the JAXB representation of an Xml Element

Compile and run the above program. This will produce the following result:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<Employee id="1">

<age>12</age>

<name>Prabhat</name>

</Employee>


Example 2: XML to Object (Un-marshaling)

import javax.xml.bind.annotation.XmlAttribute;

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement(name="Employee")

publicclass Employee{

String name;

intage;

intid;

public String getName(){

returnname;

}

@XmlElement(name="name")

publicvoid setName(String name){

this.name = name;

}

publicint getAge(){

returnage;

}

@XmlElement(name = "age")

publicvoid setAge(int age){

this.age = age;

}

publicint getId(){

returnid;

}

@XmlAttribute(name="id")

publicvoid setId(int id){

this.id = id;

}

}

 

import java.io.File;

import javax.xml.bind.JAXBContext;

import javax.xml.bind.Unmarshaller;

publicclass EmployeeMain {

publicstaticvoid main(String[] args) {

try {

JAXBContext context = JAXBContext.newInstance(Employee.class);

Unmarshaller unmarshaller = context.createUnmarshaller();

/*

* 1-way

StringBuffer buffer = new StringBuffer("<?xml version='1.0' encoding='UTF-8' standalone='yes'?><Employee id='1'><age>12</age><name>Prabhat</name></Employee>");

Employee e = (Employee)unmarshaller.unmarshal(new StreamSource(new StringReader(buffer.toString())));

*/

/*

* 2-way

*

*/

Employee e = (Employee)unmarshaller.unmarshal(new File("employee.xml"));

System.out.println(e.getName());

System.out.println(e.getId());

System.out.println(e.getAge());

} catch (Exception e) {

e.printStackTrace();

}

}

}

employee.xml

<?xml version='1.0' encoding='UTF-8' standalone='yes'?>

<Employee id='1'>

<age>12</age>

<name>Prabhat</name>

</Employee>

Output

Prabhat
1
12

Example 3: One to Many Relationship

 

Store.java

import java.util.ArrayList;

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlElementWrapper;

import javax.xml.bind.annotation.XmlRootElement;

import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name="Store")

@XmlType(propOrder={"name","books"})

publicclass Store {

private String name;

private ArrayList<Book> books;

public String getName() {

return name;

}

publicvoid setName(String name) {

this.name = name;

}

@XmlElement(name = "Book")

@XmlElementWrapper(name="booklist")

public ArrayList<Book> getBooks() {

returnbooks;

}

publicvoid setBooks(ArrayList<Book> books) {

this.books = books;

}

}



Book.java


import javax.xml.bind.annotation.XmlAttribute;

import javax.xml.bind.annotation.XmlElement;

import javax.xml.bind.annotation.XmlRootElement;

import javax.xml.bind.annotation.XmlType;

@XmlRootElement(name="Book", namespace="default")

@XmlType(propOrder={"name","author"})

public class Book {

private String name;

private String author;

private int id;

@XmlElement

public void setName(String name) {

this.name = name;

}

public String getName() {

return name;

}

@XmlElement

public void setAuthor(String author) {

this.author = author;

}

public String getAuthor() {

return author;

}

@XmlAttribute

public void setId(int id){

this.id = id;

}

public int getId(){

return id;

}

}

 

import java.util.ArrayList;

import javax.xml.bind.JAXBContext;

import javax.xml.bind.JAXBException;

import javax.xml.bind.Marshaller;

public class StoresBookDemo {

public static void main(String[] args) {

Store store = new Store();

store.setName("Saraswati Book Store");

Book java = new Book();

java.setName("JAVA");

java.setAuthor("Kethi Sera");

java.setId(1);

Book c = new Book();

c.setName("C++");

c.setAuthor("Bala Gurushwami");

c.setId(1);

ArrayList<Book> books =new ArrayList<Book>();

books.add(java);

books.add(c);

store.setBooks(books);

try {

/*// One way

// create JAXBElement of type Student

//Pass it the student object

JAXBElement<Student> jaxbElement = new JAXBElement(

new QName(Student.class.getSimpleName()), Student.class, student);

//Create a String writer object which will be

//used to write jaxbElment XML to string

StringWriter writer = new StringWriter();

// create JAXBContext which will be used to update writer

JAXBContext context = JAXBContext.newInstance(Student.class);

// marshall or convert jaxbElement containing student to xml format

context.createMarshaller().marshal(jaxbElement, writer);

//print XML string representation of Student object

System.out.println( writer.toString() ); */

// 2nd way

JAXBContext context = JAXBContext.newInstance(Store.class);

Marshaller marshel = context.createMarshaller();

marshel.marshal(store, System.out);

} catch (JAXBException e) {

e.printStackTrace();

}

}

}

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>

<Store xmlns:ns2="default">

<name>Saraswati Book Store</name>

<booklist>

<Book id="1">

<name>JAVA</name>

<author>Kethi Sera</author>

</Book>

<Book id="1">

<name>C++</name>

<author>Bala Gurushwami</author>

</Book>

</Store>