DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Please enter at least three characters to search
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Last call! Secure your stack and shape the future! Help dev teams across the globe navigate their software supply chain security challenges.

Modernize your data layer. Learn how to design cloud-native database architectures to meet the evolving demands of AI and GenAI workloads.

Releasing software shouldn't be stressful or risky. Learn how to leverage progressive delivery techniques to ensure safer deployments.

Avoid machine learning mistakes and boost model performance! Discover key ML patterns, anti-patterns, data strategies, and more.

Related

  • Extracting Data From Very Large XML Files With X-definition
  • What Is Ant, Really?
  • XML Processing Made Easy with Ballerina
  • A Review of DataWeave 2.0 Selectors

Trending

  • Unlocking Data with Language: Real-World Applications of Text-to-SQL Interfaces
  • How the Go Runtime Preempts Goroutines for Efficient Concurrency
  • Blue Skies Ahead: An AI Case Study on LLM Use for a Graph Theory Related Application
  • How to Practice TDD With Kotlin
  1. DZone
  2. Coding
  3. Languages
  4. JAXB and Root Elements

JAXB and Root Elements

By 
Blaise Doughan user avatar
Blaise Doughan
·
Aug. 12, 12 · Interview
Likes (15)
Comment
Save
Tweet
Share
224.4K Views

Join the DZone community and get the full member experience.

Join For Free

@XmlRootElement is an annotation that people are used to using with JAXB (JSR-222).  It's purpose is to uniquely associate a root element with a class.  Since JAXB classes map to complex types, it is possible for a class to correspond to multiple root elements. In this case @XmlRootElement can not be used and people start getting a bit confused.  In this post I'll demonstrate how @XmlElementDecl can be used to map this use case.
XML Schema
The XML schema below contains three root elements:  customer, billing-address, and shipping-address.  The customer element has an anonymous complex type, while billing-address and shipping-address are of the same named type (address-type).

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    targetNamespace="http://www.example.org/customer"
    xmlns="http://www.example.org/customer"
    elementFormDefault="qualified">

    <xs:element name="customer">
        <xs:complexType>
            <xs:sequence>
                <xs:element ref="billing-address"/>
                <xs:element ref="shipping-address"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="address-type">
        <xs:sequence>
            <xs:element name="street" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>

    <xs:element name="billing-address" type="address-type"/>

    <xs:element name="shipping-address" type="address-type"/>

</xs:schema

Generated Model
Below is a JAXB model that was generated from the XML schema.  The same concepts apply when adding JAXB annotations to an existing Java model.
Customer 
JAXB domain classes correspond to complex types.  Since the customer element had an anonymous complex type the Customer class has an @XmlRootElement annotation.  This is because only one XML element can be associated with an anonymous type.

package org.example.customer;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {"billingAddress","shippingAddress"})
@XmlRootElement(name = "customer")
public class Customer {

    @XmlElement(name = "billing-address", required = true)
    protected AddressType billingAddress;

    @XmlElement(name = "shipping-address", required = true)
    protected AddressType shippingAddress;

    public AddressType getBillingAddress() {
        return billingAddress;
    }

    public void setBillingAddress(AddressType value) {
        this.billingAddress = value;
    }

    public AddressType getShippingAddress() {
        return shippingAddress;
    }

    public void setShippingAddress(AddressType value) {
        this.shippingAddress = value;
    }

}


AddressType 
Again because JAXB model classes correspond to complex types, a class is generated for the address-type complex type.  Since multiple root level elements could exist for this named complex type, it is not annotated with @XmlRootElement.

package org.example.customer;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "address-type", propOrder = {"street"})
public class AddressType {

    @XmlElement(required = true)
    protected String street;

    public String getStreet() {
        return street;
    }

    public void setStreet(String value) {
        this.street = value;
    }

}

ObjectFactory
The @XmlElementDecl annotation is used to represent root elements that correspond to named complex types.  It is placed on a factory method in a class annotated with @XmlRegistry (when generated from an XML schema this class is always called ObjectFactory).  The factory method returns the domain object wrapped in an instance of JAXBElement.  The JAXBElement has a QName that represents the elements name and namespace URI.

package org.example.customer;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.*;
import javax.xml.namespace.QName;

@XmlRegistry
public class ObjectFactory {

    private final static QName _BillingAddress_QNAME = new QName("http://www.example.org/customer", "billing-address");
    private final static QName _ShippingAddress_QNAME = new QName("http://www.example.org/customer", "shipping-address");

    public ObjectFactory() {
    }

    public Customer createCustomer() {
        return new Customer();
    }

    public AddressType createAddressType() {
        return new AddressType();
    }

    @XmlElementDecl(namespace = "http://www.example.org/customer", name = "billing-address")
    public JAXBElement<AddressType> createBillingAddress(AddressType value) {
        return new JAXBElement<AddressType>(_BillingAddress_QNAME, AddressType.class, null, value);
    }

    @XmlElementDecl(namespace = "http://www.example.org/customer", name = "shipping-address")
    public JAXBElement<AddressType> createShippingAddress(AddressType value) {
        return new JAXBElement<AddressType>(_ShippingAddress_QNAME, AddressType.class, null, value);
    }

}

package-info
The package-info class is used to specify the namespace mapping (see JAXB & Namespaces).

@XmlSchema(namespace = "http://www.example.org/customer", elementFormDefault = XmlNsForm.QUALIFIED)
package org.example.customer;

import javax.xml.bind.annotation.*;

Unmarshal Operation
Now we look at the impact of the type of root element when unmarshalling XML.

customer.xml
Below is a sample XML document with customer as the root element.  Remember the customer element had an anonymous complex type.

<?xml version="1.0" encoding="UTF-8"?>
<customer xmlns="http://www.example.org/customer">
    <billing-address>
        <street>1 Any Street</street>
    </billing-address>
    <shipping-address>
        <street>2 Another Road</street>
    </shipping-address>
</customer>

shipping.xml
Here is a sample XML document with shipping-address as the root element.  The shipping-address element had a named complex type.

<?xml version="1.0" encoding="UTF-8"?>
<shipping-address xmlns="http://www.example.org/customer">
    <street>2 Another Road</street>
</shipping-address>
Unmarshal Demo 

When unmarshalling XML that corresponds to a class annotated with @XmlRootElement you get an instance of the domain object.  But when unmarshalling XML that corresponds to a class annotated with @XmlElementDecl you get the domain object wrapped in an instance of JAXBElement.   In this example you may need to use the QName from the JAXBElement to determine if you unmarshalled a billing or shipping address.

package org.example.customer;

import java.io.File;
import javax.xml.bind.*;

public class UnmarshalDemo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance("org.example.customer");
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        // Unmarshal Customer
        File customerXML = new File("src/org/example/customer/customer.xml");
        Customer customer = (Customer) unmarshaller.unmarshal(customerXML);

        // Unmarshal Shipping Address
        File shippingXML = new File("src/org/example/customer/shipping.xml");
        JAXBElement<AddressType> je = (JAXBElement<AddressType>) unmarshaller.unmarshal(shippingXML);
        AddressType shipping = je.getValue();
    }

}

Unmarshal Demo - JAXBIntrospector

If you don't want to deal with remembering whether the result of the unmarshal operation will be a domain object or JAXBElement, then you can use the JAXBIntrospector.getValue(Object) method to always get the domain object.

package org.example.customer;

import java.io.File;
import javax.xml.bind.*;

public class JAXBIntrospectorDemo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance("org.example.customer");
        Unmarshaller unmarshaller = jc.createUnmarshaller();

        // Unmarshal Customer
        File customerXML = new File("src/org/example/customer/customer.xml");
        Customer customer = (Customer) JAXBIntrospector.getValue(unmarshaller
                .unmarshal(customerXML));

        // Unmarshal Shipping Address
        File shippingXML = new File("src/org/example/customer/shipping.xml");
        AddressType shipping = (AddressType) JAXBIntrospector
                .getValue(unmarshaller.unmarshal(shippingXML));
    }

}
Marshal Operation 

You can directly marshal an object annotated with @XmlRootElement to XML.  Classes corresponding to @XmlElementDecl annotations must first be wrapped in an instance of JAXBElement.  The factory method you you annotated with @XmlElementDecl is the easiest way to do this.  The factory method is in the ObjectFactory class if you generated your model from an XML schema.

package org.example.customer;

import javax.xml.bind.*;

public class MarshalDemo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance("org.example.customer");
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);

        // Create Domain Objects
        AddressType billingAddress = new AddressType();
        billingAddress.setStreet("1 Any Street");
        Customer customer = new Customer();
        customer.setBillingAddress(billingAddress);

        // Marshal Customer
        marshaller.marshal(customer, System.out);

        // Marshal Billing Address
        ObjectFactory objectFactory = new ObjectFactory();
        JAXBElement<AddressType> je =  objectFactory.createBillingAddress(billingAddress);
        marshaller.marshal(je, System.out);
    }

}

Output
Below is the output from running the demo code.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer xmlns="http://www.example.org/customer">
    <billing-address>
        <street>1 Any Street</street>
    </billing-address>
</customer>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<billing-address xmlns="http://www.example.org/customer">
    <street>1 Any Street</street>
</billing-address>

Element XML

Published at DZone with permission of Blaise Doughan, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Extracting Data From Very Large XML Files With X-definition
  • What Is Ant, Really?
  • XML Processing Made Easy with Ballerina
  • A Review of DataWeave 2.0 Selectors

Partner Resources

×

Comments
Oops! Something Went Wrong

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • support@dzone.com

Let's be friends:

Likes
There are no likes...yet! 👀
Be the first to like this post!
It looks like you're not logged in.
Sign in to see who liked this post!