1) Introduction
JAXB (Java API for XML Binding) technology which was included as part of JWSDP (Java Web Services Developer Pack) before, is now included with the Mustang Distribution. Simply put, it is a Mapping Technology for Java and XML Documents. Using JAXB, one can Generate XML Documents from Java Objects and also they can Construct Java Objects from one or more XML Documents. In JAXB terms, Marshalling refers to the process of converting a Java Object to a XML Document and Un-Marshalling is the reverse of Marshalling which is simply getting a Java Object from one or more XML Documents.
also read:
Let us see along with Samples how to work with Marshalling and Un-Marshalling with JAXB.
2) Generating XML Documents from Java Objects
Assume that you want to have a XML Representation of a Java object. Using JAXB Marshalling you can do with much ease and the following Sample Application illustrates the same,
Person.java
package net.javabeat.articles.java6.newfeatures.jaxb; import java.util.Date; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement() public class Person { private String name; private int age; private Date dateOfBirth; private String type; public Person(){ } public Person(String name, int age, Date dateOfBirth, String type) { this.name = name; this.age = age; this.dateOfBirth = dateOfBirth; this.setType(type); } @XmlElement() public String getName() { return name; } public void setName(String name) { this.name = name; } @XmlElement() public int getAge() { return age; } public void setAge(int age) { this.age = age; } @XmlElement() public Date getDateOfBirth() { return dateOfBirth; } public void setDateOfBirth(Date dateOfBirth) { this.dateOfBirth = dateOfBirth; } @XmlAttribute() public String getType() { return type; } public void setType(String type) { this.type = type; } }
The above Person class has various properties namely ‘name’, ‘age’, ‘dateOfBirth’ and ‘type’ and objects of this Class are the targets we wish to Marshal. The Person class is annotated with @XmlRootElement since we want the name of the Class to be the Root Node. We want ‘name’, ‘age’, and ‘dateOfBirth’ as Child Elements so it has been tagged with @XmlElement. Since we want ‘type’ to appear as an Attribute we had tagged that as @XmlAttribute.
Java2XML.java
package net.javabeat.articles.java6.newfeatures.jaxb; import java.io.FileWriter; import java.util.*; import javax.xml.bind.*; public class Java2XML { public Java2XML() { } public static void main(String args[]) throws Exception{ JAXBContext context = JAXBContext.newInstance(Person.class); Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); Person person = new Person( "Anonymous", 32, new Date(1970, 1, 10), "employee"); marshaller.marshal(person, new FileWriter(".\\src\\Person.xml")); } }
JAXBContext serves as the Entry Point for making use of the JAXB API. It is initiated by the list of Class objects whose objects want to be represented as XML Documents. Then an instance of Marshaller is created by calling JAXBContext.createMarshaller() method. The Java object of type Person is marshalled into the XML Document by calling the Marshaller.marshall() method. Since we want the XML Document to look Well-indented, we have set the property Marshaller.JAXB_FORMATTED_OUTPUT to true.
A file named Person.xml would have got generated and following is the listing of that file,
Person.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <person type="employee"> <age>32</age> <dateOfBirth>1970-01-10 T00:00:00+05:30</dateOfBirth> <name>Anonymous</name> </person>
3) Representing Java Objects from XML Documents
In the previous section, we saw how to generate an XML Document from a Java Object. Now, let us see the Unmarshalling process here. As mentioned, Unmarshalling is the process of representing Java Objects from a XML Document. The process of Unmarshalling is a bit complicated as so many steps are involved. Let us break the steps one by one in greater detail.
3.1) Creating the XML Schema Definition File
If Java Classes represent the templates wherein objects can be created for a particular type, then in XML World, it is the XML Schema Definition File through which XML Document Instances can be instantiated. The first thing before creating a XML Document is to create a XML Schema and then to attach the Schema to a XML Document Instance. Let us look into a sample XML Schema File called Items, which will contain a list of ‘Item’ Elements along with its ‘Name’ and ‘Price’. Following is the listing of that File.
Items.xsd
<?xml version="1.0" encoding="UTF-8"?> <xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified"> <xs:element name="Items"> <xs:complexType> <xs:sequence> <xs:element maxOccurs="unbounded" ref="Item"/> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Item"> <xs:complexType> <xs:sequence> <xs:element ref="Name"/> <xs:element ref="Price"/> </xs:sequence> <xs:attribute name="id" use="required" type="xs:NCName"/> </xs:complexType> </xs:element> <xs:element name="Name" type="xs:string"/> <xs:element name="Price" type="xs:string"/> </xs:schema>
The above is the XML Schema Definition File which represents a list of Items. Since ‘Items’ element contain a list of Item elements and ‘Item’ element in turn contains both ‘Name’ and ‘Price’ Element, both these elements are Composite Elements and the same is represented by complexType elements.
3.2) Generating Java Files from the Schema Definition Files
Now, its time to generate the Java Source Files from this XML Schema Definition File. Mustang comes with a Utility called xjc (which stands for XML to Java Compiler) which generates Java Source Files when given a XML Schema File. Xjc is nothing but a bat file location in the bin directory of the Java 6 Installation Path. Run the following command to generate the Java Source Files.
xjc –p net.javabeat.articles.java6.newfeatures.jaxb Items.xsd
The only argument to xjc is the name of the XML Schema File which is represented by Items.xsd and the ‘-p’ option specifies the package to which the generated Java Files have to be associated. This results is the generation of the following source files.
Item.java
package net.javabeat.articles.java6.newfeatures.jaxb; import javax.xml.bind.annotation.*; import javax.xml.bind.annotation.adapters.*; import net.javabeat.articles.java6.newfeatures.jaxb.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "name", "price" }) @XmlRootElement(name = "Item") public class Item { @XmlElement(name = "Name") protected String name; @XmlElement(name = "Price") protected String price; @XmlAttribute(required = true) @XmlJavaTypeAdapter(CollapsedStringAdapter.class) protected String id; public String getName() { return name; } public void setName(String value) { this.name = value; } public String getPrice() { return price; } public void setPrice(String value) { this.price = value; } public String getId() { return id; } public void setId(String value) { this.id = value; } }
This file is just a Data file for the corresponding ‘Item’ element which contains getter and setter methods with properly instructed Annotations. Note that the two sub-elements namely ‘name’ and ‘type’ has been tagged with @XmlElement Annotation and the attribute ‘id’ has been tagged with @XmlAttribute Annotation.
Items.java
package net.javabeat.articles.java6.newfeatures.jaxb; import java.util.*; import javax.xml.bind.annotation.*; import net.javabeat.articles.java6.newfeatures.jaxb.*; @XmlAccessorType(XmlAccessType.FIELD) @XmlType(name = "", propOrder = { "item" }) @XmlRootElement(name = "Items") public class Items { @XmlElement(name = "Item") protected List<Item> item; public List<Item> getItem() { if (item == null) { item = new ArrayList<Item>(); } return this.item; } }
This is the Container Class for the Item element and it just contains a getter for the Item object. Note how the list of ‘Item’ elements in the Schema Document has been mapped to List of Item (List<Item>) elements. This is the Default Mapping given by the Sun’s Reference Implementation for JAXB.
ObjectFactory.java
package net.javabeat.articles.java6.newfeatures.jaxb; import javax.xml.bind.JAXBElement; import javax.xml.bind.annotation.XmlElementDecl; import javax.xml.bind.annotation.XmlRegistry; import javax.xml.namespace.QName; import net.javabeat.articles.java6.newfeatures.jaxb.Item; import net.javabeat.articles.java6.newfeatures.jaxb.Items; import net.javabeat.articles.java6.newfeatures.jaxb.ObjectFactory; @XmlRegistry public class ObjectFactory { private final static QName _Price_QNAME = new QName("", "Price"); private final static QName _Name_QNAME = new QName("", "Name"); public ObjectFactory() { } public Item createItem() { return new Item(); } public Items createItems() { return new Items(); } @XmlElementDecl(namespace = "", name = "Price") public JAXBElement<String> createPrice(String value) { return new JAXBElement<String>(_Price_QNAME, String.class, null, value); } @XmlElementDecl(namespace = "", name = "Name") public JAXBElement<String> createName(String value) { return new JAXBElement<String>(_Name_QNAME, String.class, null, value); } }
As guessed from its name, this is the Factory Class for creating various elements like ‘Items’, ‘Item’, ‘Name’ and Price’. Appropriate methods are available for creating ‘Items’, ‘Item’, ‘Name’ and ‘Price’ in the form of ObjectFactory.createItems(), ObjectFactory.createItem(), ObjectFactory.createName() and ObjectFactory.createPrice() respectively.
3.3) Creating a Sample XML Document
Now let us create a Sample XML Document against the Schema Definition File Items.xsd. Following is the sample XML file called Items.xml. Note how the XML Document Instance is related with the XML Schema Definition File with the help of ‘xsi:noNamespaceSchemaLocation’ attribute.
Items.xml
<Items xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xsi:noNamespaceSchemaLocation='file:C:/Items.xsd'> <Item id="LAP001"> <Name>Laptop</Name> <Price>4343$</Price> </Item> <Item id="TV001"> <Name>Television</Name> <Price>433$</Price> </Item> <Item id="DVD001"> <Name>DVD Player</Name> <Price>763$</Price> </Item> </Items>
3.4) Unmarshalling the XML Document to construct the Java object
The code to Unmarshall the XML Document is given below. The code first represents a JAXBContext object by passing in a Context Path which is usually the package name where the compiled Java Class files are located. Then an Unmarshaller object is created by calling JAXBContext.createUnmarshaller() which does the unmarshalling operation by calling the Unmarshaller.unmarshall() method passing in the XML File. Then the object is iterated over the get the actual data contents from the XML File.
XML2Java.java
package net.javabeat.articles.java6.newfeatures.jaxb; import java.io.*; import javax.xml.bind.*; public class XML2Java { public static void main(String args[]) throws Exception{ JAXBContext context = JAXBContext.newInstance( "net.javabeat.articles.java6.newfeatures.jaxb"); Unmarshaller unmarshaller = context.createUnmarshaller(); Items items = (Items)unmarshaller.unmarshal( new FileReader(".\\src\\Items.xml")); List listOfItems = items.getItem(); for(Item item : listOfItems){ System.out.println("Name = " + item.getName() + ", Price = " + item.getPrice() + ", Id = " + item.getId()); } } }
Following is the output of the above program
Name = Laptop, Price = 4343$, Id = LAP001 Name = Television, Price = 433$, Id = TV001 Name = DVD Player, Price = 763$, Id = DVD001
4) Conclusion
This article covered the leftover features of the Part I New features of Java 6. Starting with Pluggable Annotation Processing API, it covered what Annotations are, then guided us how to write Custom Annotations and Custom Annotation Processor. Then it traversed over the Cursor API and the Event Iterator API of StaX such as how to read XML Documents along with well-defined samples. Finally through Java API for XML Binding, it details how to map Java and XML Documents with some sample applications.