Sunday, July 5, 2015

JAXB Unmarshalling Example

1. Introduction

1.1 Apologies

Hey!

It's been a loooong time since my last post, so, first of all, let me apologize for this absence

The reasons:
  • The tiny OCAJP badge that you see in the right side of the blog (I will refer to this tin a forthcoming post).
  • I currently have limited time available.

1.2 Example's concept

What we 're gonna see today is how to convert an XML document to a Java Object. This (and the reverse - Java object to XML transformation) usually occurs when a software deals with Web Services.

2. The Example

We 'll here demonstrate how to convert an xml list of objects to a Java object. This can be easier using the JAXB Technology. JAXB stands for Java Architecture for XML Binding. It is used to convert XML to Java objects and vice-versa.

Environment used:
  • JDK 1.7
  • Eclipse Luna

I've the environment that I used, as from JDK versions 1.6 and later, the JAXB dependency is bundled into the JDK, in contrast with previous JDK versions, where you had to at least include the following dependencies onto your classpath: “jaxb-api.jar” and “jaxb-impl.jar”.

That is, we here don't have to include nothing at all.

Here is the project structure of this sample, a simple one as you can see, too:


2.1 The XML file

As I said, we 'll here deal with a smartphones list, so, just for demonstration purposes, two smartphones are here listed:

smartphones.xml
<?xml version="1.0" encoding="UTF-8"?>
<smartphones>
 <smartphone>
  <make>Samsung</make>
  <model>Galaxy Ace</model>
  <androidVersion>2.2</androidVersion>
 </smartphone>
 <smartphone>
  <make>Motorola</make>
  <model>Moto G 2014</model>
  <androidVersion>5.0.1</androidVersion>
 </smartphone>
</smartphones>

2.2 The Beans

Each smartphone can be described with a DTO class, so here it is:

Smartphone.java
package com.toubou91.jaxb.example;

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

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "smartphone")
public class Smartphone {

 private String make;
 private String model;
 private String androidVersion;
 
 // Getters and setters.
 public String getMake() {
  return make;
 }
 public void setMake(String make) {
  this.make = make;
 }
 public String getModel() {
  return model;
 }
 public void setModel(String model) {
  this.model = model;
 }
 public String getAndroidVersion() {
  return androidVersion;
 }
 public void setAndroidVersion(String androidVersion) {
  this.androidVersion = androidVersion;
 }
 
 @Override
 public String toString() {
  return "Smartphone [make: " + getMake() + ", model: " + getModel() + ", android version: "
     + getAndroidVersion() + "]" ;
 }
}

This is about a bean class containing JAXB annotations, in order to easily handle the properties we want to be traversed from/to XML. According to this When a top level class is annotated with @XmlRootElement maps a class or an enum type to an XML element (in our case,  the <smartphone> tag).

 @XmlAccessorType controls default serialization of fields and properties. That is, it allows us to configure the use of fields or properties to access the data in our domain object (Smartphone object). This is specified as an XmlAccessType (PUBLIC_MEMBER, PROPERTY, FIELD, or NONE) via the  @XmlAccessorType annotation. We use access type FIELD to cause JAXB implementations to create bindings for fields and annotated properties. So in our case all fields (make, model, androidVersion) are marshalled/unmarshalled by JAXB.

The toString() method has to be overrided in order to get a human-readable output format. Otherwise, for each object that will be manipulated, the output will be something like Smartphone@4bbc148 .

We obviously need a second class that holds a list of Smartphone objects:

Smartphones.java
package com.toubou91.jaxb.example;

import java.util.ArrayList;
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;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "smartphones")
public class Smartphones {
 @XmlElement(name = "smartphone", type = Smartphone.class)
 private List<smartphones> smartphones = new ArrayList<smartphones>();
 
 public Smartphones() {}
 
 public Smartphones(List<smartphones> smartphones) {
  this.smartphones = smartphones;
 }
 
 public void setSmartphones(List<smartphones> smartphones) {
  this.smartphones = smartphones;
 }
 
 public List<smartphones> getSmartphones() {
  return smartphones;
 }
}

2.3 The Helper class

Let's create a helper class to easily unmarshalla requested XML file.

JAXBXMLController.java
package com.toubou91.jaxb.example;

import java.io.File;
import java.util.List;

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

public class JAXBXMLController {

 public static List<smartphones> unmarshal(File file) throws JAXBException {
  Smartphones smartphones = new Smartphones();
  
  JAXBContext jaxbContext = JAXBContext.newInstance(Smartphones.class);
   Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
  smartphones = (Smartphones) jaxbUnmarshaller.unmarshal(file);
   
  return smartphones.getSmartphones();
  
 }
}

2.4 The Demo

Finally, let's test what we just created!

Demo.java
package com.toubou91.jaxb.example;

import java.io.File;
import java.util.List;

import javax.xml.bind.JAXBException;

public class Demo {

	public static void main(String[] args) {

		List<smartphones> smartphones = null;
		
		try {
			smartphones = JAXBXMLController.unmarshal(new File("src/smartphones.xml"));
		} catch (JAXBException e) {
			e.printStackTrace();
		}
		
		System.out.println(smartphones);
	}
}

3. Git repo

You can also find the corresponding source code in this github repo.