Marshalling- How to convert Java Objects to XML using JAXB

HOME

This tutorial explains how to use JAXB (Java Architecture for XML Binding) to convert Java Objects to XML documents.

JAXB provides a fast and convenient way to marshal (write) Java Objects into XML and un-marshal (read) XML into Java Objects. It supports a binding framework that maps XML elements and attributes to Java fields and properties using Java annotations.

With Java releases lower than Java 11, JAXB was part of the JVM and you could use it directly without defining additional libraries.

As of Java 11, JAXB is not part of the JRE anymore, and you need to configure the relevant libraries via your dependency management system, for example, either Maven or Gradle.

Configure the Java compiler level to be at least 11 and add the JAXB dependencies to your pom file.

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

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.example</groupId>
  <artifactId>JAXBDemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>

  <name>JAXBDemo</name>
  <url>http://www.example.com</url>

  <properties>  
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <maven.compiler.plugin.version>3.11.0</maven.compiler.plugin.version>
    <maven.surefire.plugin.version>3.2.1</maven.surefire.plugin.version>
    <maven.compiler.source>17</maven.compiler.source>
    <maven.compiler.target>17</maven.compiler.target>
  </properties>

  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.13.2</version>
      <scope>test</scope>
  </dependency>
    
 <dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>4.0.4</version>
   </dependency>
 </dependencies>
   
<build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>${maven.surefire.plugin.version}</version>
        <configuration>
          <testFailureIgnore>true</testFailureIgnore>
        </configuration>
      </plugin>

      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>${maven.compiler.plugin.version}</version>
        <configuration>
          <source>${maven.compiler.source}</source>
          <target>${maven.compiler.target}</target>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

JAXB Annotations

  1. @XmlRootElement: Define the root element for an XML tree
  2. @XmlType: Define the order in which the fields are written in the XML file
  3. @XmlElement: Define the actual XML element name which will be used
  4. @XmlAttribute: Define the id field is mapped as an attribute instead of an element
  5. @XmlTransient: Annotate fields that we don’t want to be included in XML

Sample XML Structure

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<EmployeeDetails>
    <firstName>Vibha</firstName>
    <lastName>Singh</lastName>
    <gender>female</gender>
    <age>30</age>
    <maritalStatus>married</maritalStatus>
    <designation>Manager</designation>
    <contactNumber>+919999988822</contactNumber>
    <emailId>abc@test.com</emailId>
    <GrossSalary>75000.0</GrossSalary>
</EmployeeDetails>

Marshalling

Marshalling provides a client application the ability to convert a JAXB derived Java object tree into XML data.

Let’s see the steps to convert Java Objects into XML document.

  1. Create POJO Class of XML
  2. Create the JAXBContext object
  3. Create the Marshaller objects
  4. Create the content tree by using set methods
  5. Call the marshal method

Now, let us create the Java Objects (POJO).

import jakarta.xml.bind.annotation.*;

@XmlRootElement(name = "EmployeeDetails")
@XmlAccessorType(XmlAccessType.FIELD)

//Define the order in which the fields are written in XML
@XmlType(propOrder = { "firstName", "lastName", "gender", "age", "maritalStatus", "designation", "contactNumber",
		"emailId", "salary" })

public class Employee {

	private String firstName;
	private String lastName;
	private int age;

    @XmlElement(name = "GrossSalary")
	private double salary;
	private String designation;
	private String contactNumber;
	private String emailId;
	private String gender;
	private String maritalStatus;

	// Getter and setter methods
	public String getFirstName() {
		return firstName;
	}

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

	public String getLastName() {
		return lastName;
	}

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

	public int getAge() {
		return age;
	}

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

	public double getSalary() {
		return salary;
	}

	public void setSalary(double salary) {
		this.salary = salary;
	}

	public String getDesignation() {
		return designation;
	}

	public void setDesignation(String designation) {
		this.designation = designation;
	}

	public String getContactNumber() {
		return contactNumber;
	}

	public void setContactNumber(String contactNumber) {
		this.contactNumber = contactNumber;
	}

	public String getEmailId() {
		return emailId;
	}

	public void setEmailId(String emailId) {
		this.emailId = emailId;
	}

	public String getGender() {
		return gender;
	}

	public void setGender(String gender) {
		this.gender = gender;
	}

	public String getMaritalStatus() {
		return maritalStatus;
	}

	public void setMaritalStatus(String maritalStatus) {
		this.maritalStatus = maritalStatus;
	}

   @Override
	public String toString() {
		return "Employee [FirstName=" + firstName + ", LastName=" + lastName + ", Age=" + age + ", Salary=" + salary
				+ ", Designation=" + designation + ", ContactNumber=" + contactNumber + ", EmailId=" + emailId
				+ ", Gender=" + gender + ", MaritalStatus=" + maritalStatus + "]";
	}
}

Create the following test program for writing the XML file.

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.PropertyException;
import org.junit.Test;
import java.io.StringWriter;

public class SerializationDemo {

    @Test
    public void serializationTest1() {

        try {

            Employee employee = new Employee();

            employee.setFirstName("Terry");
            employee.setLastName("Mathew");
            employee.setAge(30);
            employee.setSalary(75000);
            employee.setDesignation("Manager");
            employee.setContactNumber("+919999988822");
            employee.setEmailId("abc@test.com");
            employee.setMaritalStatus("married");
            employee.setGender("female");

            // Create JAXB Context
            JAXBContext context = JAXBContext.newInstance(Employee.class);

            // Create Marshaller
            Marshaller jaxbMarshaller = context.createMarshaller();

            // Required formatting
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            // Write XML to StringWriter
            StringWriter sw = new StringWriter();
            jaxbMarshaller.marshal(employee, sw);

            // Convert XML to String
            String xmlContent = sw.toString();
            System.out.println(xmlContent);

        } catch (PropertyException e) {
            e.printStackTrace();

        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

When we run the code above, we may check the console output to verify that we have successfully converted Java object to XML:

By default, the Marshaller uses UTF-8 encoding when generating XML data.

The javax.xml.bind.JAXBContext class provides a client’s entry point to JAXB API. By default, JAXB does not format the XML document. This saves space and prevents that any white-space may accidentally be interpreted as significant.

To have JAXB format the output, we simply set the Marshaller.JAXB_FORMATTED_OUTPUT property to true on the Marshaller. The marshal method uses an object and an output file where to store the generated XML as parameters.

You can see that we have used JAXB Annotations like @XMLRootElement are changed from Employee to EmployeeDetails.

The order of elements in the XML is defined by

@XmlType(propOrder = { "firstName", "lastName", "gender", "age", "maritalStatus", "designation", "contactNumber","emailId", "salary" })

@XMLElement has set the element name to GrossSalary from Salary.

The below example is the short way of writing the same test and saving XML. We need to add a constructor in the POJO class so that we can set the values to the variables through the Constructor.

import jakarta.xml.bind.annotation.*;

@XmlRootElement(name = "EmployeeDetails")
@XmlAccessorType(XmlAccessType.FIELD)

//Define the order in which the fields are written in XML
@XmlType(propOrder = { "firstName", "lastName", "gender", "age", "maritalStatus", "designation", "contactNumber",
        "emailId", "salary" })

public class Employee {

    private String firstName;
    private String lastName;
    private int age;

    @XmlElement(name = "GrossSalary")
    private double salary;
    private String designation;
    private String contactNumber;
    private String emailId;
    private String gender;
    private String maritalStatus;

    public Employee() {
        super();

    }

    public Employee(String firstName, String lastName, int age, double salary, String designation, String contactNumber,
                    String emailId, String gender, String maritalStatus) {

        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;


        this.salary = salary;

        this.designation = designation;
        this.contactNumber = contactNumber;
        this.emailId = emailId;
        this.gender = gender;
        this.maritalStatus = maritalStatus;
    }

    // Getter and setter methods
    public String getFirstName() {
        return firstName;
    }

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

    public String getLastName() {
        return lastName;
    }

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

    public int getAge() {
        return age;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    public String getContactNumber() {
        return contactNumber;
    }

    public void setContactNumber(String contactNumber) {
        this.contactNumber = contactNumber;
    }

    public String getEmailId() {
        return emailId;
    }

    public void setEmailId(String emailId) {
        this.emailId = emailId;
    }

    public String getGender() {
        return gender;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public String getMaritalStatus() {
        return maritalStatus;
    }

    public void setMaritalStatus(String maritalStatus) {
        this.maritalStatus = maritalStatus;
    }

    @Override
    public String toString() {
        return "Employee [FirstName=" + firstName + ", LastName=" + lastName + ", Age=" + age + ", Salary=" + salary
                + ", Designation=" + designation + ", ContactNumber=" + contactNumber + ", EmailId=" + emailId
                + ", Gender=" + gender + ", MaritalStatus=" + maritalStatus + "]";
    }
}

The below JAXB example for XML marshalling convert Java objects into an XML.

import jakarta.xml.bind.JAXBContext;
import jakarta.xml.bind.JAXBException;
import jakarta.xml.bind.Marshaller;
import jakarta.xml.bind.PropertyException;
import org.junit.Test;
import java.io.File;
import java.io.StringWriter;

public class SerializationDemo {


    @Test
    public void serializationTest2() {

        try {

            Employee employee = new Employee("Thomas", "Pawsey", 35, 100000, "Director", "+919999988822","Test@test.com", "married", "female");

            // Create JAXB Context
            JAXBContext context = JAXBContext.newInstance(Employee.class);

            // Create Marshaller
            Marshaller jaxbMarshaller = context.createMarshaller();

            // Required formatting
            jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);

            // Write XML to StringWriter
            StringWriter writer = new StringWriter();
            jaxbMarshaller.marshal(employee, writer);

            // Convert XML to String
            String xmlContent = writer.toString();
            System.out.println(xmlContent);

            // Save the file
            String userDir = System.getProperty("user.dir");
            jaxbMarshaller.marshal(employee, new File(userDir + "\\src\\test\\resources\\JAXB_XML.xml"));
            System.out.println("File is saved");
            
        } catch (PropertyException e) {
            e.printStackTrace();

        } catch (JAXBException e) {
            e.printStackTrace();
        }
    }
}

When we run the code above, we may check the console output to verify that we have successfully converted Java object to XML:

The XML is saved under src/test/resources. To see this file, after the execution of the test, you need to refresh the project.

Similarly, we can unmarshal an XML to Java Objects in the next tutorial.

We are done! Congratulations on making it through this tutorial and hope you found it useful! Happy Learning!!

Leave a comment