Scenario
Suppose your application fetches a record from a database and it needs to create an XML out of it. There are chances that your application uses an ORM framework such as Hibernate and the database record is fetched in the form of entity classes. Now you have two ways, iterate over the object properties and create each XML node manually using the XML DOM apis (How to create XML from Java program using DOM parser) or follow the approach detailed here.
How ?
The method discussed here uses JAXB (Java Architecture For XML Binding). JAXB is a java framework which has the ability to map classes to XML elements and vice-versa. It provides options to convert java objects to XML and XML to java objects provided they have been properly mapped to each other. The process of converting objects to XML is called marshalling and the conversion of XML to objects is called unmarshalling (How to convert XML to object using JAXB) in JAXB terms.
Suppose you want to create following XML structure from a java program :
<?xml version=”1.0″ encoding=”UTF-8″ standalone=”yes”?>
<Employees>
<Employee>
<department>dev</department>
<name>codippa</name>
</Employee>
<Employee>
<department>qa</department>
<name>emp1</name>
</Employee>
<Employee>
<department>service</department>
<name>emp2</name>
</Employee>
<Employee>
<department>support</department>
<name>emp3</name>
</Employee>
</Employees>
If you visualize this XML structure and co-relate this with java objects then you can see that this XML is a collection of employees and each employee has two attributes (or fields), department and name. Thus, you can map this XML to two classes
- Employees.java – This will be the root of XML and should contain a list of employees.
- Employee.java – This class should contain two fields namely
department
andname
.
Let’s design our java classes based on above concept.
Employees.java
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name="Employees")
public class Employees {
private List<Employee> employee;
@XmlElement(name="Employee")
public List<Employee> getEmployee() {
return employee;
}
public void setEmployee(List<Employee> employeeList) {
this.employee = employeeList;
}
}
Details
Employees.java class is annotated with @XmlRootElement
which implies that it will be the root of the generated XML document. name
attribute of this element specifies the name with which the root node of XML will be created and is optional. If it is not given then root will be created by the name of the class in lower-case letters (that is, employees).
The class also contains a list of Employee
objects with its getter method annotated with @XmlElement
which specifies that the elements of this class will be the nodes of the XML with each node named as Employee. Again, the name
attribute of this annotation is optional and specifies the name with which the child nodes will be created. If not given, the child nodes will be created by the name of Employee
class in lower case.
Employee.java
import javax.xml.bind.annotation.XmlElement;
public class Employee {
private String department;
private String name;
@XmlElement
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
@XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Details
The above class contains two fields department
and name
whose getter methods are annotated with @XmlElement
.This annotation signifies that these fields will become nodes in the generated XML and will be the children of the class node which contains them. By default the nodes will be created by the name of fields. If you want some other name for the nodes, then provide name
attribute of this annotation with the desired value as shown in Employees class.
Moving Ahead
We also need to write code which shall create Employee
objects, populate their values and adds them to a list. Further, there will also be marshalling code to convert above list of objects to XML. Following code creates the list of employees to be converted to XML:
public static void main(String[] args) throws IOException {
// create first employee
Employee e1 = new Employee();
e1.setName("codippa");
e1.setDepartment("dev");
// create second employee
Employee e2 = new Employee();
e2.setName("emp1");
e2.setDepartment("qa");
// create third employee
Employee e3 = new Employee();
e3.setName("emp2");
e3.setDepartment("service");
// create fourth employee
Employee e4 = new Employee();
e4.setName("emp3");
e4.setDepartment("support");
// initialize employee list
List<Employee> list = new ArrayList<Employee>();
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
// initialize root object
Employees employeeData = new Employees();
// set employee list
employeeData.setEmployee(list);
}
The below code converts the list of employees to XML.
JAXBContext context = JAXBContext.newInstance(Employees.class);
Marshaller m = context.createMarshaller();
// for pretty-print XML in JAXB
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
StringWriter writer = new StringWriter();
// Write to list to a writer
m.marshal(list, writer);
String result = writer.toString();
// write the content to a physical file
new FileWriter("jaxbTest.xml").write(result);
Details
In order to convert object to XML, first create an object of javax.xml.bind.JAXBContext
class using its static newInstance
method. This method takes a list of one or more top-level classes. Top-level means which should be made the root of generated XML. In our case, it is Employees. Object of javax.xml.bind.JAXBContext
is then used to create an object of javax.xml.bind.Marshallar
which is responsible for converting java object graph to XML. Its marshal
method takes the final object which contains all the data to be written to an XML and a java.io.Writer
object. Thus object of any class which extends java.io.Writer
may be passed to this method. In above example we pass an object of java.io.StringWriter
and the result of marshalling is written to the String which is then written to the file.
Learn How to write String to file in various ways
Let’s tweak in:
@XmlElement
annotation may also be applied over field names rather than their getter methods. In that case an annotation@XmlAccessorType(XmlAccessType.FIELD)
needs to be applied at the class level.- In order to directly write to a file without using a String, just pass a
java.io.FileWriter
object with the appropriate file path to themarshal
method. marshal
method ofjavax.xml.bind.Marshaller
takes ajava.io.Writer
object as its second argument which means that you have flexibility of directly writing it to a file or writing it to a string and then writing that string to a file.- If your XML nodes need to have attributes such as of the form
<Employee id="1">
then this may be achieved by adding anid
field to Employee class and annotating it with@XmlAttribute
annotation. - Even if a field in your JAXB annotated classes is not annotated with
@XmlElement
annotation, it is included in the generated XML by default. If you want to skip a field from being included in the XML, mark it with@XmlTransient
annotation. - All JAXB code used above throws
javax.xml.bind.JAXBException
. Either handle it usingtry-catch
blocks or throw it. - Nodes will be generated by the field or class names in lower-case by default. To change the names of generated nodes, use
name
attribute alongwith@XmlRootElement
or@XmlElement
annotations.
Been till Here !!! Move a bit further to comment, share and love this post…