JAXB Binding and Unmarshalling Example

0

In this example, we will show you how to use JAXB (Java Architecture for XML Binding) to bind an XML document with the corresponding JAXB classes.

The mapping is defined by the JAXB annotated fields specified in the POJO classes.

The XML document to be bound is then fed to the JAXB binding framework for unmarshalling. The unmarshalling process generates a content tree of data objects instantiated from the JAXB annotated classes.

XML document to be unmarshalled using JAXB

Below is a simple XML document that contains the company and its employee details.

company.xml:

<?xml version="1.0"?>
<!DOCTYPE company SYSTEM "classpath://dtd/company.dtd">
<company>
	<name>XYZ</name>
	<employees>
		<employee id="1" dept="Eng" designation="Developer">
			<name>Joe</name>
			<age>34</age>
		</employee>
		<employee id="2" dept="Eng" designation="QA">
			<name>Sam</name>
			<age>24</age>
		</employee>
		<employee id="3" dept="Eng" designation="Architect">
			<name>John</name>
			<age>44</age>
		</employee>
		<employee id="4" dept="HR" designation="Manager">
			<name>Sam</name>
			<age>24</age>
		</employee>		
	</employees>
	<department id="Eng">Engineering</department>
	<department id="HR">HR & Admin</department>
</company>

Define schema or DTD

company.dtd:

For this example, we have defined a dtd.

<!ELEMENT company (name, employees, department*)>

<!ELEMENT name (#PCDATA)>
<!ELEMENT employees (employee*)>

<!ELEMENT employee (name, age)>
<!ATTLIST employee id CDATA #REQUIRED>
<!ATTLIST employee dept CDATA #IMPLIED>
<!ATTLIST employee designation (Developer|QA|Architect|BusinessAnalyst|Manager) #REQUIRED>
 
<!ELEMENT age (#PCDATA)>

<!ELEMENT department (#PCDATA)>
<!ATTLIST department id CDATA #REQUIRED>

You also need a to implement an XMLResolver in order to resolve the dtd resource.

DtdResolver:

package com.javarticles.jaxb;

import java.io.InputStream;

import javax.xml.stream.XMLStreamException;

public class DtdResolver implements javax.xml.stream.XMLResolver{

    @Override
    public Object resolveEntity(String publicID, String systemID,
            String baseURI, String namespace) throws XMLStreamException {
        if ( systemID != null ) {
            if ( systemID.startsWith( "classpath://" ) ) {
                final String path = systemID.substring( "classpath://".length() );
                final InputStream stream = getClass().getClassLoader().getResourceAsStream(path);                
                return stream;
            }
        }
        return null;
    }
}

Define JAXB classes

Define JAXB annotated classes starting with the root element <company>. It contains a list of departments and employees.

JaxbCompany:

package com.javarticles.jaxb;

import java.util.List;

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

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="", propOrder={"name", "companyEmployees", "department"})
@XmlRootElement(name="company")
public class JaxbCompany {
    private String name;
    @XmlElement(name="employees", required=true)
    private JaxbEmployees companyEmployees;
    private List<JaxbDepartment> department;
    
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public JaxbEmployees getCompanyEmployees() {
        return companyEmployees;
    }
    public void setCompanyEmployees(JaxbEmployees companyEmployees) {
        this.companyEmployees = companyEmployees;
    }
    public List<JaxbDepartment> getDepartment() {
        return department;
    }
    public void setDepartment(List<JaxbDepartment> department) {
        this.department = department;
    }       
    public String toString() {
        return "Company(" + name + ", " + companyEmployees + ", " + department + ")";
    }
}

Define JAXB employees class that contain list of employees. Each employee is represented by a JAXB class.

JaxbEmployees:

package com.javarticles.jaxb;

import java.util.List;

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

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name="", propOrder={"employee"})
public class JaxbEmployees {
    @XmlElement
    private List<JaxbEmployee> employee;

    public List<JaxbEmployee> getEmployees() {
        return employee;
    }

    public void setEmployees(List<JaxbEmployee> employees) {
        this.employee = employees;
    }    
    
    public String toString() {
        return "employees(" + employee + ")";
    }
}

Here is the JAXB class for the department.

JaxbDepartment:

package com.javarticles.jaxb;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.XmlValue;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = { "value" })
public class JaxbDepartment {
    @XmlValue
    protected String value;
    @XmlAttribute(name = "id", required = true)
    protected String id;

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }
    
    public String toString() {
        return "Dep(" + id + ", " + value + ")";
    }
}

JAXB class for employee contains the ID, name, department ID and the designation enum.

JaxbEmployee:

package com.javarticles.jaxb;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlType;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder={"name", "age"})
public class JaxbEmployee {
    private int age;

    private String name;
    
    @XmlAttribute(name = "id")
    private String empId;
    
    @XmlAttribute(name = "dept")
    private String departmentId;
    
    @XmlAttribute(name = "designation", required=true)
    private JaxbDesignationEnum designation;
    
    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    public String getEmpId() {
        return empId;
    }

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

    public String getDepartmentId() {
        return departmentId;
    }

    public void setDepartmentId(String departmentId) {
        this.departmentId = departmentId;
    }    
    
    public String toString() {
        return "Employee(" + empId  + ", " + name + ", " + age + ", " + departmentId + ", " + designation.value() + ")";
    }
}

Define the designation enum.

JaxbDesignationEnum:

package com.javarticles.jaxb;

import javax.xml.bind.annotation.XmlEnum;
import javax.xml.bind.annotation.XmlEnumValue;
import javax.xml.bind.annotation.XmlType;

@XmlType(name = "")
@XmlEnum
public enum JaxbDesignationEnum {
    @XmlEnumValue("Developer")
    DEVELOPER("Developer"), @XmlEnumValue("QA")
    QA("QA"), @XmlEnumValue("Architect")
    ARCHITECT("Architect"), @XmlEnumValue("BusinessAnalyst")
    BUSINESS_ANALYSYST("BusinessAnalyst"), @XmlEnumValue("Manager")
    MANAGER("Manager");

    private final String value;

    JaxbDesignationEnum(String v) {
        value = v;
    }

    public String value() {
        return value;
    }

    public static JaxbDesignationEnum fromValue(String v) {
        for (JaxbDesignationEnum c : JaxbDesignationEnum.values()) {
            if (c.value.equals(v)) {
                return c;
            }
        }
        throw new IllegalArgumentException(v);
    }

}

Unmarshal XML into JAXB content tree

The JAXB binding framework must know the classes that need to be bound. In the below example, we just provide the top level class representing the root element. It will automatically figure out other dependent JAXB classes based on the annotated members.

JAXBContext jaxbContext = JAXBContext
                    .newInstance(JaxbCompany.class);

The JAXBContext class provides the client’s entry point to the JAXB API in order to create the entire content tree.
Next step is to create an Unmarshaller object that can be used to convert XML data into a java content tree.

Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

Finally, we unmarshall. The unmarshal() method assumes that the parser is on a START_DOCUMENT or START_ELEMENT event. In this example, the parser is iterated till the start element is found.

            while (event != null && !event.isStartElement()) {
                staxEventReader.nextEvent();
                event = staxEventReader.peek();
            }

Unmarshalling will be done from this start event to the corresponding end event.

JaxCompany jaxCompany = (JaxbCompany) unmarshaller.unmarshal(staxEventReader);

JaxbUnmarshallingExample:

package com.javarticles.jaxb;

import java.io.InputStream;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.XMLEvent;

public class JaxbUnmarshallingExample {
    public static void main(String[] args) {
        System.out.println("start unmarshalling "
                + JaxbUnmarshallingExample.class
                        .getResourceAsStream("company.xml"));
        JaxbCompany company = unmarshal(JaxbUnmarshallingExample.class
                .getResourceAsStream("company.xml"));
        System.out.println(company);
    }

    public static JaxbCompany unmarshal(InputStream stream) {
        try {
            XMLInputFactory staxFactory = XMLInputFactory.newInstance();
            staxFactory.setXMLResolver(new DtdResolver());
            XMLEventReader staxReader = staxFactory
                    .createXMLEventReader(stream);
            try {
                return unmarshal(staxReader);
            } finally {
                try {
                    staxReader.close();
                } catch (Exception ignore) {
                }
            }
        } catch (XMLStreamException e) {
            throw new RuntimeException("Unable to create stax reader", e);
        }
    }

    private static JaxbCompany unmarshal(XMLEventReader staxEventReader) {
        XMLEvent event;
        try {
            event = staxEventReader.peek();
            while (event != null && !event.isStartElement()) {
                staxEventReader.nextEvent();
                event = staxEventReader.peek();
            }
        } catch (Exception e) {
            throw new RuntimeException("Error accessing stax stream", e);
        }

        if (event == null) {
            throw new RuntimeException("Could not locate root element");
        }

        try {
            JAXBContext jaxbContext = JAXBContext
                    .newInstance(JaxbCompany.class);
            Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
            return (JaxbCompany) unmarshaller.unmarshal(staxEventReader);
        } catch (JAXBException e) {
            throw new RuntimeException(
                    "Unable to perform unmarshalling at line number " + e);
        }
    }
}

Output:

start unmarshalling java.io.BufferedInputStream@15db9742
company name: Company(XYZ, employees([Employee(1, Joe, 34, Eng, Developer), Employee(2, Sam, 24, Eng, QA), Employee(3, John, 44, Eng, Architect), Employee(4, Sam, 24, HR, Manager)]), [Dep(Eng, Engineering), Dep(HR, HR & Admin)])

Download the source code

This was an example about JAXB binding and unmarshalling.

You can download the source code here: jaxbUnmarshallingExample.zip

About Author

Ram's expertise lies in test driven development and re-factoring. He is passionate about open source technologies and loves blogging on various java and open-source technologies like spring. You can reach him at rsatish.m@gmail.com

Comments are closed.