Pages

July 30, 2013

JAXB - Marshal Element Missing @XmlRootElement Annotation


jaxb logo
Information on the root XML element is required when 'marshalling to' or 'unmarshalling from' a Java object. JAXB provides this information via the @XmlRootElement annotation which contains the name and namespace of the root XML element.

When trying to marshal a class which does not have a @XMLRootElement annotation defined, following error will be thrown: "unable to marshal as an element because it is missing an @XmlRootElement annotation". Alternatively when trying to unmarshal, the Java runtime will report that an "unsuspected element" is found.


For this example let’s use following class representing a car with a basic structure. Note that a XmlRootElement is not defined!
package com.codenotfound.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 new Car 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 "com.codenotfound.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("com.codenotfound.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="com.codenotfound.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. Lets reuse the XML representation of a car that we generated in the previous section.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:car id="DEF-456" xmlns:ns2="com.codenotfound.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. Note that it is also possible to use JAXB to create an object from an XML String instead of using a file.
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:"com.codenotfound.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]


github logo
If you would like to run the above code sample you can get the full source code here.

This concludes the marshal & unmarshal with missing @XmlRootElement annotation code samples. If you found this post helpful or have any questions or remarks, please leave a comment below.

23 comments:

  1. Very Helpful. Thanks a lot!!

    ReplyDelete
  2. Helped me. Much Thanks.

    ReplyDelete
  3. This is a really nice tutorial. Thank you!

    ReplyDelete
  4. For people like me, who want to unmarshal from a string can use:

    JAXBElement root = jaxbUnmarshaller.unmarshal(new StreamSource(new StringReader(serializedText)), Car.class);
    Car car = root.getValue();

    Very Helpful. Thanks again.

    ReplyDelete
    Replies
    1. finally it worked, thanks to you :)

      Delete
    2. It is not working for me, can anyone help me ? I'm looking to unmarshal from string xml as mentioned here but it is not working. Here is my code:
      String formattedXML= "truetrue00000111199745610102.370.0010102.3730.000.00BNSCCASH0falseCASHEQUCAD7101.312.480000027101.317101.317101.3101316671CAD CashLiquidités CADCAD CashLiquidités CADBNSCSHBL1falseCASHEQUCAD1800.000.1500BNS21800.001800.001800.0001316678Cashable GICCPG encaissableBNS Cashable GICCPG encaissable Scotia11111161Y42017-06-062016-06-06001CSHBCAD1800.00N1800.00BNSCSHBL1falseCASHEQUCAD1201.060.1500BNS21200.001200.001201.0601316679Cashable GICCPG encaissableBNS Cashable GICCPG encaissable Scotia11111161Y52017-06-062016-06-06001CSHBCAD1200.00N1200.00000001111997456NRSHTBNSBNEThe Bank of Nova ScotiaLa Banque de Nouvelle-ÉcosseHome Owner TrustFiducie - propriétaireHome Owner TrustFiducie - propriétaire33993010102.370.0010102.372016-06-06Bfalse1299392true";
      JAXBContext contextJAXB = JAXBContext.newInstance(PlanHoldingsResponse.class);
      Unmarshaller unmarshaller = contextJAXB.createUnmarshaller();
      JAXBElement root = unmarshaller.unmarshal(new StreamSource(new StringReader(
      formattedXML)), PlanHoldingsResponse.class);
      planHoldingResp = root.getValue();
      System.out.println("Result:" + planHoldingResp);

      Thank you in advance !!

      Delete
    3. Never post any customer-specific data in your post...

      Delete
  5. Helped me . Thank you. I will follow this blog.

    ReplyDelete
  6. thanks, very clear example

    ReplyDelete
  7. Is 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".



    ReplyDelete
  8. Thank you! Great help.

    ReplyDelete
  9. thanks for your sharing and posts.

    ReplyDelete
  10. forget about the JAXBElement, 'JAXBIntrospector.getValue(u.unmarshal(...);' returns Car object, it does not matter it is defined as JAXBElement or not.

    ReplyDelete
  11. This is a very good article I have used it and send to ppl in need soooo many times.
    GREAT JOB!

    ReplyDelete
  12. When trying the above code to Marshal, I am getting below exception:

    cannot find constructor JAXBElement(com.sun.org.apache.xml.internal.utils.QName,java.lang.Class,java.util.List)

    Though the constructor is present in JAXBElement.java
    Any clue why this is not working?

    ReplyDelete
    Replies
    1. What are you passing as third parameter to the constructor? It should be an Object created from the Class you specified in the second parameter.

      Delete