JAXB Marshal Java Objects without @XmlRootElement

Lokesh Gupta

Many times, we will need to marshal Java objects without JAXB annotations such as @XmlRootElement 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.

There can be many other such situations but the idea is that we are not able to modify the model class with JAXB annotations. This can be an example of converting Java objects to XML without JAXB.

1. Problem while Marshalling without @XmlRootElement

In such case, if we try to marshal the Java object to XML directly then we will get an error like “unable to marshal type T as an element because it is missing an @XmlRootElement annotation“.

javax.xml.bind.MarshalException
 - with linked exception:
[com.sun.istack.internal.SAXException2: unable to marshal type "com.howtodoinjava.demo.model.Employee" 
as an element because it is missing an @XmlRootElement annotation]
  at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:311)
  at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.marshal(MarshallerImpl.java:236)
  at javax.xml.bind.helpers.AbstractMarshallerImpl.marshal(AbstractMarshallerImpl.java:95)
  at com.howtodoinjava.demo.JaxbExample.jaxbObjectToXML(JaxbExample.java:45)
  at com.howtodoinjava.demo.JaxbExample.main(JaxbExample.java:17)
Caused by: com.sun.istack.internal.SAXException2: unable to marshal type "com.howtodoinjava.demo.model.Employee" 
as an element because it is missing an @XmlRootElement annotation
  at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.reportError(XMLSerializer.java:234)
  at com.sun.xml.internal.bind.v2.runtime.ClassBeanInfoImpl.serializeRoot(ClassBeanInfoImpl.java:323)
  at com.sun.xml.internal.bind.v2.runtime.XMLSerializer.childAsRoot(XMLSerializer.java:479)
  at com.sun.xml.internal.bind.v2.runtime.MarshallerImpl.write(MarshallerImpl.java:308)
  ... 4 more

Where Employee.java class is a POJO class and does not have the JAXB annotations 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, setters, getters

}

2. Solution to marshal an object without @XmlRootElement

In absence of @XmlRootElement annotation, JAXB is not able to build JAXBElement instance for Employee object. So that’s where we have to help JAXB to construct it manually. Then we can convert this JAXBElement to XML.

2.1. Maven

Start with adding the latest ‘jakarta‘ dependencies for adding the JAXB support (Java 11 onwards).

<dependencies>
  <dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.0</version>
  </dependency>
</dependencies>

<dependencies>
  <dependency>
    <groupId>com.sun.xml.bind</groupId>
    <artifactId>jaxb-impl</artifactId>
    <version>4.0.3</version>
    <scope>runtime</scope>
  </dependency>
</dependencies>

2.2. Syntax

/**
  * @param name          Java binding of xml element tag name
  * @param declaredType  Java binding of xml element declaration's type
  * @param value         Java instance representing xml element's value
  */
JAXBElement<T> elem = new JAXBElement(QName name, Class<T> declaredType, T value );

For example –

JAXBElement<Employee> jaxbElement 
        = new JAXBElement<Employee>( new QName("", "employee"), Employee.class, employeeInstance);

jaxbMarshaller.marshal(jaxbElement, System.out);

3. Demo

Now let’s see how this marshalling code works. We are creating an instance of the above Employee class and converting in to XML.

import com.howtodoinjava.demo.model.Department;
import com.howtodoinjava.demo.model.Employee;
 
public class JaxbExample 
{
  public static void main(String[] args) 
  {
    Employee employee = new Employee(1, "Lokesh", "Gupta", new Department(101, "IT"));
     
    jaxbObjectToXML( employee );
  }
   
  private static void jaxbObjectToXML(Employee employeeObj) 
  {
      try {
          JAXBContext jaxbContext = JAXBContext.newInstance(Employee.class);
          Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
 
          // To format XML
          jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE); 
 
          //If we DO NOT have JAXB annotated class
          JAXBElement<Employee> jaxbElement = 
            new JAXBElement<Employee>( new QName("", "employee"), 
                      Employee.class, 
                      employeeObj);
             
          jaxbMarshaller.marshal(jaxbElement, System.out);
           
          //If we had JAXB annotated class
          //jaxbMarshaller.marshal(employeeObj, System.out);  
           
      } catch (JAXBException e) {
          e.printStackTrace();
      }
  }
}

Program Output:

<?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>

Drop me your questions related to JAXB marshal without @XmlRootElement example.

Happy Learning !!

Source Code on Github

Comments

Subscribe
Notify of
guest
4 Comments
Most Voted
Newest Oldest
Inline Feedbacks
View all comments

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.