Using JAXB for XML with Java
11 CommentsJava Architecture for XML Binding (JAXB) is a library that helps to bind XML schemas and Java representations. JAXB provides you with a mechanism to marshal Java objects into XML and the other way around – unmarshal XML into Java objects.
XML is an industry standard for defining the contents of your message. XML along with Java are complementary technologies to exchange data across the Internet. When you work with XML, you need a way to take an XML file, and then convert it into some sort of data structure, which your program can manipulate. You also need to serialize the state of your Java objects into XML. JAXB is one library that performs such marshalling and unmarshalling operations.
In this post, I will discuss on how to marshal Java objects into XML and the other way around using JAXB.
Using JAXB to Marshall Java Objects to XML
Let us consider a scenario where we need to model a product for an e-commerce store. Apart from fields, such as product Id, description, image URL, and price, a Product
object is also composed of a User
object that represents the user who adds the product to the store.
Our intent is to marshal the Product
object, along with its composed User
object into XML by using JAXB.
We can start by creating a User
POJO to model the user.
User.java
package guru.springframework.blog.domain; public class User { private Long id; private String name; private String email; public User() { } public User(Long id, String name, String email) { this.id = id; this.name = name; this.email = email; } public Long getId() { return id; } public User setId(Long id) { this.id = id; return this; } public String getName() { return name; } public User setName(String name) { this.name = name; return this; } public String getEmail() { return email; } public User setEmail(String email) { this.email = email; return this; } @Override public String toString() { final StringBuffer sb = new StringBuffer("User{"); sb.append("id=").append(id); sb.append(", name='").append(name).append('\''); sb.append(", email='").append(email).append('\''); sb.append('}'); return sb.toString(); } }
User
is a simple POJO with the id, name, and email fields, along with their corresponding getter and setter methods.
Next, we will create the Product
POJO. While creating this POJO, we will use annotations introduced in JAXB 2.0 to control how our Product
object is marshalled to XML.
Note: As from JDK 1.6, JAXB is bundled with JDK. Therefore you don’t need to add any dependency for it.
The code of the Product
POJO is this.
Product.java
package guru.springframework.blog.domain; import javax.xml.bind.annotation.*; import java.math.BigDecimal; @XmlRootElement(name = "product") //@XmlAccessorType(XmlAccessType.FIELD) public class Product { @XmlAttribute(name = "id") private String productId; @XmlElement(name = "description") private String description; @XmlElement(name = "imageUrl") private String imageUrl; @XmlElement(name = "price") private BigDecimal price; @XmlElement(name = "createdBy") private User createdBy; public Product(){} public Product(String productId, String description, String imageUrl, BigDecimal price, User createdBy) { this.productId = productId; this.description = description; this.imageUrl = imageUrl; this.price = price; this.createdBy = createdBy; } @Override public String toString() { return "Product{" + "\n productId='" + productId + '\'' + ",\n description='" + description + '\'' + ",\n imageUrl='" + imageUrl + '\'' + ",\n price=" + price + ",\n createdBy=" + createdBy +"\n"+ '}'; } }
In this Product
class, we used a number of JAXB annotations. They are:
@XmlRootElement
: This annotation is used at the top level class to indicate the root element in the XML document. Thename
attribute in the annotation is optional. If not specified, the class name is used as the root XML element in the document.@XmlAttribute
: This annotation is used to indicate the attribute of the root element.@XmlElement
: This annotation is used on the properties of the class which will be the sub-elements of the root element.
The Product
POJO is now ready to be marshalled into XML. To do so, let us write a JUnit test class. If you are new to JUnit, I suggest going through my Unit Testing with JUnit series.
The test class is this.
ProductToXmlTest.java
package guru.springframework.blog.marshal; import guru.springframework.blog.domain.Product; import guru.springframework.blog.domain.User; import org.junit.After; import org.junit.Before; import org.junit.Test; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import java.io.File; import java.io.FileNotFoundException; import java.math.BigDecimal; public class ProductToXmlTest { private Product product; @Before public void setUp() { long l = 10; Long longId = new Long(l); User user = new User(longId, "John", "[email protected]"); product = new Product("PO1", "Spring Guru Mug", "http://springframework.guru/wp-content/uploads/2015/04/spring_framework_guru_shirt-rf412049699c14ba5b68bb1c09182bfa2_8nax2_512.jpg", new BigDecimal(18.95), user); } @After public void tearDown() { product = null; } @Test public void testObjectToXml() throws JAXBException, FileNotFoundException { JAXBContext jaxbContext = JAXBContext.newInstance(Product.class); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); marshaller.marshal(product, new File("product.xml")); marshaller.marshal(product, System.out); } }
In this code:
- Line 19 – Line 24: Instantiates and initializes a
User
and aProduct
object in thesetup()
method marked as@Before
. - Line 33: The
JAXBContext.newInstance()
method obtains aJAXBContext
for theProduct
class which you want to marshal.JAXBContext
provides the entry point for the JAXB API. - Line 34: Creates a
Marshaller
through a call to thecreateMarshaller()
method ofJAXBContext
. In JAXB, theMarshaller
class governs the process of marshalling Java objects into XML data through its various marshalling methods. - Line 35: Configures the
Marshaller
. Thetrue
value of theJAXB_FORMATTED_OUTPUT
property instructs theMarshaller
to generate the XML with proper indentation. - Line 36: Calls the
marshal()
method on theMarshaller
with the initializedProduct
object and the file to write the XML. - Line 37: Marshals the object to the “standard” output stream.
On running the ProductToXmlTest
class, a product.xml
file gets generated.
The output of the test is this.
Using JAXB to Unmarshall XML into Java Objects
Unmarshalling XML with JAXB to a Java object involves creating an Unmarshaller
on the JAXBContext
and calling the unmarshal()
method. This method accepts the XML file to unmarshall.
The JUnit test class to unmarshall the generated product.xml
back to the Product
and User
objects is this:
XmlToProductTest.java
package guru.springframework.blog.unmarshal; import guru.springframework.blog.domain.Product; import guru.springframework.blog.domain.User; import org.junit.After; import org.junit.Before; import org.junit.Test; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import java.io.File; import java.io.FileNotFoundException; import java.math.BigDecimal; public class XmlToProductTest { private Product product; @Test public void testXmlToObject() throws JAXBException, FileNotFoundException { File file = new File("product.xml"); JAXBContext jaxbContext = JAXBContext.newInstance(Product.class); Unmarshaller unmarshaller = jaxbContext.createUnmarshaller(); product = (Product) unmarshaller.unmarshal(file); System.out.println(product); } }
In this XmlToProductTest
class, a JAXBContext
initialized with Product
is used. The createUnmarsheller()
method returns an Unmarshaller
. A JAXB Unmarshaller
governs the process of unmarhshalling XML data into a Java object tree. Finally, the unmarshal()
method unmarshals the File object for product.xml
into the Product
POJO.
The output on running the test is this.
Handling Collections
Often you will need to marshall Java collection objects, such as List
, Set
, and Map
to XML, and also unmarshall XML back to collection objects.
Consider our current application where we now need to work with a list of products. To model the new requirement, let us create a Products
class.
The code of the Products
class is this.
Products.java
package guru.springframework.blog.domain; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; import java.util.ArrayList; import java.util.List; @XmlRootElement(name = "products") public class Products { List<Product> products; public List<Product> getProducts() { return products; } @XmlElement(name = "product") public void setProducts(List<Product> products) { this.products = products; } public void add(Product product) { if (this.products == null) { this.products = new ArrayList<Product>(); } this.products.add(product); } }
In this Products
class, the @XmlRootElement
annotation specifies the root element of the XML as products. This class has a single List
property with getter and setter methods. The add()
method of this class accepts a Product
object and adds it to the List
.
The test class to convert a list of products to XML, is this.
ProductToXmlListTest.java
package guru.springframework.blog.marshal; import guru.springframework.blog.domain.Product; import guru.springframework.blog.domain.Products; import guru.springframework.blog.domain.User; import org.junit.After; import org.junit.Before; import org.junit.Test; import javax.xml.bind.JAXBContext; import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; import java.io.File; import java.io.FileNotFoundException; import java.math.BigDecimal; public class ProductToXmlListTest { private Product product; private Product product1; @Before public void setUp(){ long l = 10; Long longId = new Long(l); User user = new User(longId,"John","[email protected]"); product = new Product("PO1", "Spring Guru Mug","http://springframework.guru/wp-content/uploads/2017/12/spring_framework_guru_mug-rf412049699c14ba5b68bb1c09182bfa2_8nax2_512.jpg", new BigDecimal(18.95),user); product1 = new Product("PO2", "Spring Guru Shirt","http://springframework.guru/wp-content/uploads/2017/12/spring_framework_guru_shirt-rf412049699c14ba5b68bb1c09182bfa2_8nax2_512.jpg", new BigDecimal(20.00),user); } @After public void tearDown(){ product = null; } @Test public void testObjectToXml() throws JAXBException, FileNotFoundException { Products products = new Products(); products.add(product); products.add(product1); JAXBContext jaxbContext = JAXBContext.newInstance(Products.class); Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,true); marshaller.marshal(products, new File("products.xml")); marshaller.marshal(products, System.out); } }
The output on running the test is this.
Summary
In this post, I have covered introductory concepts on JAXB. I have previously written a post on how to use an XML Schema and JAXB to generate Java classes for a RESTful Web services here.
JAXB also comes with a JAXB Binding compiler tool, named schemagen. You can use schemagen to generate an XSD schema from Java classes.
The source code for this post is available on github. You can download it here.
Magnus Leray
Great post! Really like the job you did. Really appreciated!!!
HS Coetzee
Hi!
Good post, thanks.
Just a mention, from java 9 it seems JAXB is no longer included on the JVM classpath by default.
Apparently for Java 9 at least, you can get it back by way of the “–add-modules” command line argument to the JVM.
From Java11 (probably) more aggressive solutions will have to be employed (such as explicitly adding an additional dependency to a JAXB provider library).
Ref:
– https://jaxenter.com/jdk-11-java-ee-modules-140674.html
– https://stackoverflow.com/questions/43574426/how-to-resolve-java-lang-noclassdeffounderror-javax-xml-bind-jaxbexception-in-j?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa
– http://mail.openjdk.java.net/pipermail/jdk9-dev/2016-May/004309.html
Armen
Really Nice post! Thank you John!
patrelleryPat
I get com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Amarender
Hi Jt
Thanks for the post and sharing knowledge with us here. If possible can you share a sample concerting complex type SOAP(includes all types, definition, binding, messages, line items etc) request into java objects( consuming soap request in spring boot service) and converting soap XML response to JSON
Shawn
The code snippets are not appearing to me. Were they removed? For example it mentions here is the code for Product pojo. But then there is an empty box.
jt
Doing some site maintenance – will be fixed soon!
Akhil K C
Is there any way we can avoid the generation of ” ”
from the xml .??
Arthur Silva de Carvalho Azevedo
Hi.
This blog post is from 2018, and I receive it in my email in October, 26 2023
JAXB is still the best choice for XML manipulation in Java?