We will often need to unmarshal Java objects that do not have JAXB annotations, and we are not permitted to make any changes in the source code. This situation may occur when we are working with legacy code or some client jar for which we do not have source code.
1. Problem when unmarshaling without JAXB annotations
In such a case, if we try to unmarshal Java object to XML directly, then we will get an error like this.
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"employee"). Expected elements are (none)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:726)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:247)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:242)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:109)
Where Employee.java
class is as below. It does not have any JAXB annotation such as @XmlRootElement
.
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private String firstName;
private String lastName;
private Department department;
//constructors, getters and setters
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", department="
+ department + "]";
}
}
2. Solution to Unmarshal without JAXB annotations
In absence of @XmlRootElement
annotation, JAXB is not able to build JAXBElement
instance for Employee
object. So that’s where you have to help JAXB to construct it manually.
/**
* Unmarshal XML data from the specified XML Source by <tt>declaredType</tt> and return the
* resulting content tree.
* @param source source the XML Source to unmarshal XML data from (providers are
* only required to support SAXSource, DOMSource, and StreamSource)
*
* @param declaredType appropriate JAXB mapped class to hold <tt>source</tt>'s xml root element
*
* @return value Java content rooted by JAXB Element
*/
public <T> JAXBElement<T> unmarshal( javax.xml.transform.Source source, Class<T> declaredType )
throws JAXBException;
For example –
JAXBElement<Employee> jaxbElement = (JAXBElement<Employee>) jaxbUnmarshaller
.unmarshal(new StreamSource(xmlFile), Employee.class);
3. Demo
Now let’s see how this unmarshalling code works.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<department>
<id>101</id>
<name>IT</name>
</department>
<firstName>Lokesh</firstName>
<id>1</id>
<lastName>Gupta</lastName>
</employee>
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.transform.stream.StreamSource;
import com.howtodoinjava.demo.model.Employee;
public class JaxbExample
{
public static void main(String[] args)
{
String fileName = "employee.xml";
jaxbXmlFileToObject(fileName);
}
private static void jaxbXmlFileToObject(String fileName)
{
File xmlFile = new File(fileName);
JAXBContext jaxbContext;
try
{
jaxbContext = JAXBContext.newInstance(Employee.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
JAXBElement<Employee> jaxbElement = (JAXBElement<Employee>) jaxbUnmarshaller
.unmarshal(new StreamSource(xmlFile), Employee.class);
Employee employee = jaxbElement.getValue();
System.out.println(employee);
}
catch (JAXBException e)
{
e.printStackTrace();
}
}
}
Program Output:
Employee [id=1, firstName=Lokesh, lastName=Gupta, department=Department [id=101, name=IT]]
Drop me your questions in the comments section.
Happy Learning !!
Leave a Reply