Easy xml parsing using java annotatoins
Java 1.5 is shipped with an annotation API (javax.xml.bind.annotation package) for Xml processing. With this API you don’t have to write code to traverse and parse xml documents. You just need to annotate your business classes with relevant xml tags. Once java classes are properly annotated and a target xml file is provided; the java xml parser populate objects from annotated classes which are injected with relevant xml values.
Here’s a simple example.
A Simple Example
Look at the following xml document that defines a shopping cart with an apple inside.
<shopping-cart name=”myShoppingCart” active=”true”>
<apple price=”12″/>
</shopping-cart>
Listing 1
Let’s try to develop an xml parser for above Document 1 using java annotations. The source code of the ShoppingCart.java and Apple.java classes would be,
@XmlAccessorType (XmlAccessType.FIELD)
@XmlRootElement (name = “test-unit”)
public class ShoppingCart {
@XmlAttribute (name = “name”)
private String name;
@XmlAttribute (name = “active”)
private boolean isActive;
@XmlElementRef
private Apple apple;
…
}
@XmlRootElement (name = “test-case”)
public class Apple {
@XmlAttribute (name = “price”)
private double price;
…
}
Listing 2
Annotations definitions
Followings are the most commonly used annotations for xml processing.
@XmlRootElement
Used at class level to annotate the class with the corresponding xml tag.
@XmlAccessorType
Used at class level. This annotation defines whether to use the field access or the property access to inject the xml elements.
@XmlElement
Used at field / property level. This one defines the mapping xml tag for a property of a java class. This element provides basic primitive data conversions (using String constructors of primitive data types) like String to int, String to boolean etc.
@XmlElements
This element is a container for multiple @XmlElement annotations. Used when a single field on a class is mapped to multiple xml tags.
@XmlElementRef
Defines a dynamic association between a java property and xml element. So the actual xml tag to java field mapping is dynamically derived at the runtime.
Complete java doc is available here http://download.oracle.com/javase/6/docs/api/javax/xml/bind/annotation/package-summary.html.
A complete example
Let’s consider a shopping cart with a lot of fruits.
<shopping-cart name=”myShoppingCart” active=”true”>
<apple price=”12″/>
<orange price=”12″/>
</shopping-cart>
Listing 3
Instead of keeping a single Apple reference inside the shopping cart we would like to keep a reference like List<Fruit> so that we can put any number of Fruits to the shopping cart. So the new source code for shopping cart is,
@XmlAccessorType (XmlAccessType.FIELD)
@XmlRootElement (name = “test-unit”)
public class ShoppingCart {
@XmlAttribute (name = “name”)
private String name;
@XmlAttribute (name = “active”)
private boolean isActive;
@XmlElementRef
private List<Fruit> fruits;
…
}
Listing 4
The implementation of Fruit, Apple and Orange classes are as follows.
//no XmlRoot element is required
public abstract class Fruit {
@XmlAttribute (name = “price”)
private double price;
…
}
@XmlRootElement (name = “apple”)
public class Apple extends Fruit{
…
}
@XmlRootElement (name = “orange”)
public class Orange {
…
}
Listing 5
When the Java xml parser encounters a <shopping-cart> tag, it will populate an instance of the ShoppingCart class. Here we have mapped the name and isActive java properties to the xml tags name and active using @XmlAttribute annotation. So the xml parser will use this mapping to inject values to the ShoppingCart instance.
Next, the xml parser will read the <apple … tag. After a no direct mapping is detected on initial lookup, it will look up for @XmlElementRef elements (Fruit class in this case). It will traverse down the class hierarchy to find a class annotated with “apple” tag (Apple class in this case) and will create an instance of that class and insert it to the Fruits list. (Same for the <orange> tag)