@XmlRootElement
annotation which contains the name and namespace of the root XML element. When trying to marshal or unmarshal a class which does not have a @XMLRootElement
annotation defined, an error will be thrown. One way to solve this problem would be by changing the class and adding the @XMLRootElement
annotation. In case the class cannot be altered, another solution is to wrap the root object in an instance of JAXBElement
. Following code sample illustrates how to implement this.For this example let’s use following class representing a car with a simple structure. Note that a
XmlRootElement
is not defined!package info.source4code.jaxb.model;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
public class Car {
private String make;
private String manufacturer;
private String id;
public String getMake() {
return make;
}
@XmlElement
public void setMake(String make) {
this.make = make;
}
public String getManufacturer() {
return manufacturer;
}
@XmlElement
public void setManufacturer(String manufacturer) {
this.manufacturer = manufacturer;
}
public String getId() {
return id;
}
@XmlAttribute
public void setId(String id) {
this.id = id;
}
public String toString() {
return "Car [" + "make=" + make + ", manufacturer=" + manufacturer
+ ", id=" + id + "]";
}
}
Marshal when @XMLRootElement is missing
Marshalling is the process of transforming the memory representation of an object to a data format suitable for storage or transmission. In the case of JAXB it means converting a Java object into XML. The below code snippet shows the creation of a newCar
instance.car = new Car();
car.setMake("Passat");
car.setManufacturer("Volkswagen");
car.setId("ABC-123");
The method below takes as input the above car object and tries to marshal it using JAXB.
public static String marshalError(Car car) throws JAXBException {
StringWriter stringWriter = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(Car.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// format the XML output
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(car, stringWriter);
String result = stringWriter.toString();
LOGGER.info(result);
return result;
}
When running the above method, the runtime returns an error as the
Car
class is missing the required @XMLRootElement
annotation.unable to marshal type "info.source4code.jaxb.model.Car" as an
element because it is missing an @XmlRootElement annotation
In order to be able to marshal the car object we need to provide a root XML element. This is done as shown below by first creating a qualified name which contains the name and namespace of the root XML element. In a next step we create a new
JAXBElement
and pass the qualified name, class and object. Using the created JAXBElement
we call the marshal()
method.public static String marshal(Car car) throws JAXBException {
StringWriter stringWriter = new StringWriter();
JAXBContext jaxbContext = JAXBContext.newInstance(Car.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// format the XML output
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
QName qName = new QName("info.source4code.jaxb.model", "car");
JAXBElement<Car> root = new JAXBElement<Car>(qName, Car.class, car);
jaxbMarshaller.marshal(root, stringWriter);
String result = stringWriter.toString();
LOGGER.info(result);
return result;
}
This time JAXB is able to successfully marshal the object and the result is the following:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:car id="ABC-123" xmlns:ns2="info.source4code.jaxb.model">
<make>Passat</make>
<manufacturer>Volkswagen</manufacturer>
</ns2:car>
Unmarshal when @XMLRootElement is missing
Unmarshalling in JAXB is the process of converting XML content into a Java object.<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:car id="DEF-456" xmlns:ns2="info.source4code.jaxb.model">
<make>Golf</make>
<manufacturer>Volkswagen</manufacturer>
</ns2:car>
In the method below we pass the above XML file and try to unmarshal it to an instance of the
Car
class.public static Car unmarshalError(File file) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(Car.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Car car = (Car) jaxbUnmarshaller.unmarshal(file);
LOGGER.info(car.toString());
return car;
}
When running the above code, the runtime returns an error as a root XML element is found (the XML has a root element) but the
Car
class does not define a @XMLRootElement
and as such it is not expected.unexpected element (uri:"info.source4code.jaxb.model", local:"car").
Expected elements are (none)
In order to be able to unmarshal the object we need to define a root XML element. This is done as shown below by first manually creating the root
JAXBElement
of type Car
by using the XML file and the class we are trying to unmarshal to. Then we create a Car
object and assign the value of the previous created root JAXBElement
.public static Car unmarshal(File file) throws JAXBException {
JAXBContext jaxbContext = JAXBContext.newInstance(Car.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
JAXBElement<Car> root = jaxbUnmarshaller.unmarshal(new StreamSource(
file), Car.class);
Car car = root.getValue();
LOGGER.info(car.toString());
return car;
}
This time JAXB is able to successfully unmarshal the object and the result is the following:
Car [make=Golf, manufacturer=Volkswagen, id=DEF-456]
If you would like to run the above code sample you can download the full source code and their corresponding JUnit test cases here.
This concludes the marshal & unmarshal with missing
@XmlRootElement
annotation code sample. If you found this post helpful or have any questions or remarks, please leave a comment.
Very Helpful. Thanks a lot!!
ReplyDeleteThanks
ReplyDeleteHelped me. Much Thanks.
ReplyDeleteThis is a really nice tutorial. Thank you!
ReplyDeleteThank you!
ReplyDeleteSUper
ReplyDeleteFor people like me, who want to unmarshal from a string can use:
ReplyDeleteJAXBElement root = jaxbUnmarshaller.unmarshal(new StreamSource(new StringReader(serializedText)), Car.class);
Car car = root.getValue();
Very Helpful. Thanks again.
Helped me . Thank you. I will follow this blog.
ReplyDeletethanks, very clear example
ReplyDeleteIs it possible to get rid of "ns2" as when I use @XmlRootElement at that time I dont get "ns2" but with dyname QName specification we get "ns2".
ReplyDeleteThank you! Great help.
ReplyDelete