Core Java

Make your JAXB cleaner with the MOXy implementation

The principle advantage of using JAXB when marshalling and demarshalling XML is the programming model. Simply annotate a few POJOs and use the JAXB API’s and you can serialise to XML and deserialise from XML very easily. You don’t need to worry about the specifics regarding how the XML is marshalled / unmarshalled. Everything is much simpler than alternatives such as DOM and SAX.

Now data in XML files tends to be hierarchial in nature. For example, conside this XML file:

<?xml version="1.0" encoding="UTF-8"?>
<person>
    <firstname>Barok</firstname>
    <lastname>Obama</lastname>
    <age>52</age>
    <car>
        <model>Green Ford Focus 1.4L</model>
    </car>
</person>

In this case, the person Barok Obama has a car which is a Green Ford Focus. Here, we see the hierarchial characteristics of XML. The Car is under the Person. In a more sophisticated example, a Person could have a Car, which has a Car Radio, which has an Amplifier, which has Transistors etc. But let’s stick with our simpler case for the moment. Suppose we want to unmarshall this XML file using JAXB. We want all the person details (firstname, lastname etc.) and the model of the car belonging to the person. We create a Person POJO and a Car POJO and annotate as appropriate.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"name", "firstname", "lastname"})
public class Person {
    private String firstname;
    private String lastname;
    private int age;
    private Car car;
  
    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 String getFirstname() {
        return firstname;
    }
  
    public void setFirstname(String name) {
        this.firstname = name;
    }
  
    public Car getCar() {
        return car;
    }
  
    public void setCar(Car car){
        this.car= car;
    }
}
public class Car {
    private String model;
     
    public String getModel() {
        return model;
    }
  
    public void setModel(String model){
        this.model = model;
    }
}

To unmarshall this we simply do

public static void unmarshall() throws Exception {
    JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
    Person person = (Person)unmarshaller.unmarshal(new File("Person.xml"));
    System.out.println("Perosn is=" +person.toString());
}

This all seems very simple – especially when you consider that the Car entity doesn’t even need any annotations! However, the Car only has one attribute and it can seem like overkill to have a POJO class for something we only want one attribute from! Remember this is a simple example, imagine if the hierarchial structure was much deeper. Something like an outer entity containing an entity, which contained another entity which contained even another entity and all we wanted was the outer entity and one attribute from very deepest nested entity. It’s essentially the same problem but just even more overkill. We would have to ensure there were POJO class for everything in the hierarchy – even for entities which we wanted nothing from. No-one likes code bloat. So what can we do?

Well the first thing we gotta remember is that JAXB is a specification for which there are many implementations for (e.g. JaxMeAPI, MOXy, Metro). If we were to use the JAXB reference implementation (shipped with the JDK, there is not much we can do). We have to have a Car and Person POJO. However, if we use the MOXy implementation from EclipseLink we can use some of its extensions to help us. More specifically we can use the MOXy @XmlPath extension which is inspired from XPath.

Let’s see it in action. Here is the updated Person POJO.

@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(propOrder={"name", "firstname", "lastname"})
public class Person {
    private String firstname;
    private String lastname;
    private int age;
  
    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 String getFirstname() {
        return firstname;
    }
  
    public void setFirstname(String name) {
        this.firstname = name;
    }
  
    @XmlPath("car/model/text()")
    private String model;
 
    public String getModel() {
        return model;
    }
}

So where’s the Car POJO gone? Well it’s deleted. We don’t need it anymore. Bye bye.
Using the MOXy @XmlPath annotation we do not need the Car POJO. This annotation resides in org.eclipse.persistence.oxm.annotations package and to get that on your classpath is really simple. If you are a maven user just add:

<dependency>
    <groupid>org.eclipse.persistence</groupId>
    <artifactid>eclipselink</artifactId>
    <version>2.3.2</version>
</dependency>

To tell your JDK to use MOXy for the JAXB implementation at runtime you put a file named
jaxb.properties in the same directory as your JAXB POJOs. It contains one line:

javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

To ensure you are using the MOXy implementation just check the JAXB context:

JAXBContext jaxbContext = JAXBContext.newInstance(Person.class);
System.out.println("jaxbContext is=" +jaxbContext.toString());

You should see something like:

jaxbContext is=org.eclipse.persistence.jaxb.JAXBContext@5e3974

After that there are no changes. The exact same unmarshalling code can be used.
One reason why I really like this extension is because it means less code. This usually means cleaner code and more maintable code. This becomes even more obvious in more complex scenarios where entities are much more deeper in hiearchial structure than this simple example. It doesn’t matter if you are using something like XJC to generate your POJOs you still got code bloat.

Remember JAXB set out to be a cleaner programming model than JAXP alternatives such as SAX and DOM but in scenarios with deep hierachies, the profileration of classes using JAXB doesn’t make it a convincingly cleaner. Remember, it would be quite easy to ignore the classes you don’t want using DOM and XPath or even just using SAX.

MOXy swings the battle for cleanliness back to JAXB by providing the ability to use XPath expressions for anything in our XML file.

Note: MOXy has just being included as JAXB implementation for WebLogic 12c.

References: 

  1. MOXy project page
  2. Blaise Doughan’s blog
  3. Make your JAXB cleaner with the MOXy implementation  from our JCG partner Alex Staveley at the Dublin’s Tech Blog

Related Articles :

Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Lulseged Zerfu
Lulseged Zerfu
10 years ago

Hi

I see that my JAXBContext is as expected org.eclipse.persistence.jaxb.JAXBContext. But how do you add XPath annotation on generated classes?

BR
Lulseged

abhijeet
abhijeet
9 years ago

JAXBContext jc = JAXBContext.newInstance(TestDataBean.class); System.out.println(“JaxbContext is:”+ jc.toString()); output: JaxbContext is:jar:file:/C:/Users/abhijeet.aute/.ivy2/cache/com.sun.xml.bind/jaxb-impl/jars/jaxb-impl-2.2.5.jar!/com/sun/xml/bind/v2/runtime/JAXBContextImpl.class Build-Id: 2.2.5 [testng] Classes known to this context: [testng] [B [testng] boolean [testng] byte [testng] char [testng] com.abc.api.constants.RatePrefrence [testng] com.abc.api.property.bean.API_PropertyDataBean [testng] com.abc.api.property.bean.API_RoomDataBean [testng] com.abc.api.property.bean.API_SearchDataBean [testng] com.abc.api.property.bean.TestDataBean [testng] com.sun.xml.bind.api.CompositeStructure [testng] double [testng] float [testng] int [testng] java.awt.Image [testng] java.io.File [testng] java.lang.Boolean [testng] java.lang.Byte [testng] java.lang.Character [testng] java.lang.Class [testng] java.lang.Double [testng] java.lang.Float [testng] java.lang.Integer [testng] java.lang.Long [testng] java.lang.Object [testng] java.lang.Short [testng] java.lang.String [testng] java.lang.Void [testng] java.math.BigDecimal [testng] java.math.BigInteger [testng] java.net.URI [testng] java.net.URL [testng] java.util.Calendar [testng] java.util.Date [testng] java.util.GregorianCalendar [testng] java.util.UUID [testng] javax.activation.DataHandler [testng] javax.xml.bind.JAXBElement [testng] javax.xml.datatype.Duration [testng] javax.xml.datatype.XMLGregorianCalendar [testng] javax.xml.namespace.QName [testng] javax.xml.transform.Source… Read more »

abhijeet
abhijeet
9 years ago
Reply to  abhijeet

as per you, it should print jaxbContext is=org.eclipse.persistence.jaxb.JAXBContext@5e3974 ?????????

Back to top button