This post shows how to perform JAXB pre and post-processing with Unmarshaller Listener. For instance, you may want to compare the contents of an object before and after you unmarshal an XML. Another use-case is when you may need to store unmarshalled values to some list not mapped to any XML
element. We can achieve it by creating a class that extends Unmarshaller Listener and overriding two methods. These methods are
beforeUnmarshal and
afterUnmarshal.
Software Requirements
- Windows 10
- Java 8 (Source Level = 1.8)
- Eclipse Mars.2 Release (4.5.2)
JAXB Unmarshaller Listener
The Unmarshaller Listener is an abstract class available in java.xml.bind.package. It has two methods.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | public static abstract class Listener { /** * <p/> * Callback method invoked before unmarshalling into <tt>target</tt>. * <p/> * <p/> * This method is invoked immediately after <tt>target</tt> was created and * before the unmarshalling of this object begins. Note that * if the class of <tt>target</tt> defines its own <tt>beforeUnmarshal</tt> method, * the class specific callback method is invoked before this method is invoked. * * @param target non-null instance of JAXB mapped class prior to unmarshalling into it. * @param parent instance of JAXB mapped class that will eventually reference <tt>target</tt>. * <tt>null</tt> when <tt>target</tt> is root element. */ public void beforeUnmarshal(Object target, Object parent) { } /** * <p/> * Callback method invoked after unmarshalling XML data into <tt>target</tt>. * <p/> * <p/> * This method is invoked after all the properties (except IDREF) are unmarshalled into <tt>target</tt>, * but before <tt>target</tt> is set into its <tt>parent</tt> object. * Note that if the class of <tt>target</tt> defines its own <tt>afterUnmarshal</tt> method, * the class specific callback method is invoked before this method is invoked. * * @param target non-null instance of JAXB mapped class prior to unmarshalling into it. * @param parent instance of JAXB mapped class that will reference <tt>target</tt>. * <tt>null</tt> when <tt>target</tt> is root element. */ public void afterUnmarshal(Object target, Object parent) { } } |
Pre And Post-Processing Person Unmarshal Listener
The PersonUnmarshallListener is our listener implementation that prints some texts and stores the name value to a list. For instance, the afterUnmarshal prints out “AFTER UNMARSHAL”, the object’s content, and then holds the person’s name on a list. For the beforeUnmarshal method, it prints out “BEFORE UNMARSHAL” and the contents of the initial object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | package com.turreta.jaxb.unmarshaller.listener; import javax.xml.bind.Unmarshaller.Listener; public class PersonUnmarshallListener extends Listener { /** * Access the created object after its fields have been set to * some values * * @param target * @param parent */ @Override public void afterUnmarshal(Object target, Object parent) { super.afterUnmarshal(target, parent); System.out.println("AFTER UNMARSHAL"); if(target instanceof Person) { Person p = (Person) target; p.getSomeList().add(p.getName()); } } /** * Access the created initial object * * @param target * @param parent */ @Override public void beforeUnmarshal(Object target, Object parent) { super.beforeUnmarshal(target, parent); System.out.println("BEFORE UNMARSHAL"); if(target instanceof Person) { Person p = (Person) target; System.out.println(p); } } } |
JAXB Model and Test XML For Pre and Post-Processing
Our Java JAXB class represents the contents of our test XML. Then, we have a list field that we annotated with @XmlTransient. As a result, this field will not be to any element in the test XML, and we will use it to store the name of the Person object.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | package com.turreta.jaxb.unmarshaller.listener; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlRootElement; import javax.xml.bind.annotation.XmlTransient; @XmlRootElement public class Person { private String name; @XmlTransient private List<String> someList = new ArrayList<>(); public List<String> getSomeList() { return someList; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Person [name=" + name + ", someList=" + someList + "]"; } } |
Below is our test XML.
1 2 3 4 | <?xml version="1.0" encoding="UTF-8"?> <person> <name>Jane Doe</name> </person> |
First, we must instantiate our listener and set it as the unmarshaller’s listener.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | package com.turreta.jaxb.unmarshaller.listener; import java.io.FileInputStream; import javax.xml.bind.JAXBContext; import javax.xml.bind.Unmarshaller; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamReader; public class DemoApp { public static void main(String[] args) throws Exception { JAXBContext jc = JAXBContext.newInstance(Person.class); XMLInputFactory xif = XMLInputFactory.newFactory(); FileInputStream xml = new FileInputStream("src/main/resources/person.xml"); XMLStreamReader xsr = xif.createXMLStreamReader(xml); Unmarshaller unmarshaller = jc.createUnmarshaller(); // Instantiate our listener PersonUnmarshallListener pul = new PersonUnmarshallListener(); // Set the unmarshaller lister to this object unmarshaller.setListener(pul); Person person = (Person) unmarshaller.unmarshal(xsr); System.out.println(person); } } |
When we run the codes, we get the following sample output. We can see the content of the JAXB object after pre and post-processing using the Unmarshaller Listener.
Download the codes for JAXB Pre and Post-processing using Unmarshaller Listener
You may download the codes from this GitHub repository that do JAXB pre and post-processing on an XML using Unmarshaller Listener.