Many times, you will need to unmarshal Java objects which does not have JAXB annotations such as @XmlRootElement
and you are not permitted to make any changes in sourcecode. This situation may occur when you are working with legacy code or some client jar for which you do not have source code.
1. Problem when unmarshal without jaxb annotations
In such case, if you try to unmarshal Java object to XML directly then you will get 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) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1131) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:556) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:538) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:153) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:509) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:379) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:605) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3138) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:880) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:606) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:117) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:510) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:848) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:777) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213) at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:649) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:157) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:162) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:171) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:189) at com.howtodoinjava.demo.JaxbExample.jaxbXmlFileToObject(JaxbExample.java:63) at com.howtodoinjava.demo.JaxbExample.main(JaxbExample.java:21)
Where Employee.java
class is as below. It does not have any JAXB annotation such as @XmlRootElement
.
package com.howtodoinjava.demo.model; import java.io.Serializable; public class Employee implements Serializable { private static final long serialVersionUID = 1L; private Integer id; private String firstName; private String lastName; private Department department; public Employee() { super(); } public Employee(int id, String fName, String lName, Department department) { super(); this.id = id; this.firstName = fName; this.lastName = lName; this.department = department; } //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 absense 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.
2.1. Syntax
/** * 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);
2.2. Unmarshalling
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>
package com.howtodoinjava.demo; 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 comments section.
Happy Learning !!
Reference : XmlRootElement Java Doc
Is there a way for this to work if the class contains fields that point to other classes, which also need to be marshalled without the XmlRootElement tag?
Hi Abby,
I have the same scenario, did you manage to get a workaround?