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

Because the DevOps movement has redefined engineering responsibilities, SREs now have to become stewards of observability strategy.

Apache Cassandra combines the benefits of major NoSQL databases to support data management needs not covered by traditional RDBMS vendors.

The software you build is only as secure as the code that powers it. Learn how malicious code creeps into your software supply chain.

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

Related

  • Inheritance in PHP: A Simple Guide With Examples
  • A Guide to Constructor Chaining in Java
  • Achieving Inheritance in NoSQL Databases With Java Using Eclipse JNoSQL
  • HTTP-Based OOP, Inheritance, and Polymorphism

Trending

  • Supervised Fine-Tuning (SFT) on VLMs: From Pre-trained Checkpoints To Tuned Models
  • Chat With Your Knowledge Base: A Hands-On Java and LangChain4j Guide
  • Traditional Testing and RAGAS: A Hybrid Strategy for Evaluating AI Chatbots
  • Monolith: The Good, The Bad and The Ugly

JAXB and Inheritance - Using XmlAdapter

By 
Blaise Doughan user avatar
Blaise Doughan
·
Feb. 02, 12 · Interview
Likes (2)
Comment
Save
Tweet
Share
45.5K Views

Join the DZone community and get the full member experience.

Join For Free

In previous posts I have covered how to map inheritance relationships in JAXB. This can be done by element name (via @XmlElementRef), by the xsi:type attribute, or in EclipseLink MOXy using another XML attribute (via @XmlDescriminatorNode/@XmlDescriminatorValue).  In this post the type indicator will be an XML attribute/element unique to that type, and we will leverage an XmlAdapter to implement this behaviour.

Input (input.xml)


In this example the possible contact methods are Address and PhoneNumber.  If the street attribute is present on the contact-method element we will instantiate an Address object, and if the number attribute is present we will instantiate a PhoneNumber object.

<?xml version="1.0" encoding="UTF-8"?>
<customer>
    <contact-method
        number="555-1111"/>
    <contact-method
        street="1 A St"
        city = "Any Town"/>
    <contact-method
        number="555-2222"/>
</customer>

Java Model

Below is the domain model that will be used for this example.

Customer

package blog.inheritance.xmladapter;
 
import java.util.List;
import javax.xml.bind.annotation.*;
 
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
 
    @XmlElement(name="contact-method")
    private List<ContactMethod> contactMethods;
 
}

ContactMethod

ContactMethod and its subclasses (Address & PhoneNumber) will be handled by an XmlAdapter, so the only mapping required is @XmlJavaTypeAdapter to specify the implementation of XmlAdapter.

package blog.inheritance.xmladapter;
 
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
 
@XmlJavaTypeAdapter(ContactMethodAdapter.class)
public abstract class ContactMethod {
 
}
Address

package blog.inheritance.xmladapter;
 
public class Address extends ContactMethod {
 
    protected String street;
    protected String city;
 
}

PhoneNumber

package blog.inheritance.xmladapter;
 
public class PhoneNumber extends ContactMethod {
 
    protected String number;
 
}

XmlAdapter (ContactMethodAdapter)

The AdaptedContactMethod class has been created and represents the combined properties of ContactMethod, Address, and PhoneNumber.  In a marshal operation only the properties corresponding to the type being marshalled are populated.  During the unmarshal operation after the AdaptedContactMethod has been built, we can look at which properties have been populated to determine the appropriate subtype that should be returned.


package blog.inheritance.xmladapter;
 
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.adapters.XmlAdapter;
 
public class ContactMethodAdapter extends
    XmlAdapter<ContactMethodAdapter.AdaptedContactMethod, ContactMethod> {
 
    @Override
    public AdaptedContactMethod marshal(ContactMethod contactMethod)
        throws Exception {
        if (null == contactMethod) {
            return null;
        }
        AdaptedContactMethod adaptedContactMethod = new AdaptedContactMethod();
        if (contactMethod instanceof Address) {
            Address address = (Address) contactMethod;
            adaptedContactMethod.street = address.street;
            adaptedContactMethod.city = address.city;
        } else {
            PhoneNumber phoneNumber = (PhoneNumber) contactMethod;
            adaptedContactMethod.number = phoneNumber.number;
        }
        return adaptedContactMethod;
    }
 
    @Override
    public ContactMethod unmarshal(AdaptedContactMethod adaptedContactMethod)
        throws Exception {
        if (null == adaptedContactMethod) {
            return null;
        }
        if (null != adaptedContactMethod.number) {
            PhoneNumber phoneNumber = new PhoneNumber();
            phoneNumber.number = adaptedContactMethod.number;
            return phoneNumber;
        } else {
            Address address = new Address();
            address.street = adaptedContactMethod.street;
            address.city = adaptedContactMethod.city;
            return address;
        }
    }
 
    public static class AdaptedContactMethod {
 
        @XmlAttribute
        public String number;
 
        @XmlAttribute
        public String street;
 
        @XmlAttribute
        public String city;
 
    }
 
}
Demo Code

The following demo code will be used for this example.  We will unmarshal the input document, output the type of each object in the collection, and then marshal the objects back to XML.
package blog.inheritance.xmladapter;
 
import java.io.File;
import javax.xml.bind.*;
 
public class Demo {
 
    public static void main(String[] args) throws Exception  {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);
 
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/blog/inheritance/xmladapter/input.xml");
        Customer customer = (Customer) unmarshaller.unmarshal(xml);
 
        for(ContactMethod contactMethod : customer.getContactMethods()) {
            System.out.println(contactMethod.getClass());
        }
 
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }
 
}

Output

The following is the output from running the demo code.  Note how each of the instances of ContactMethod in the collection are of the appropriate sub-type.


class blog.inheritance.xmladapter.PhoneNumber
class blog.inheritance.xmladapter.Address
class blog.inheritance.xmladapter.PhoneNumber
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <contact-method number="555-1111"/>
    <contact-method city="Any Town" street="1 A St"/>
    <contact-method number="555-2222"/>
</customer>
Related Forum Questions

Below are a couple of use cases that appeared on Stack Overflow that can be implemented using this approach:
  • eclipselink/Moxy : inheritance and attribute name overloading based on type
  • Jaxb objects with the same name
  • Java/JAXB: Unmarshal XML attributes to specific Java object attributes

 

From http://blog.bdoughan.com/2012/01/jaxb-and-inhertiance-using-xmladapter.html

Inheritance (object-oriented programming)

Opinions expressed by DZone contributors are their own.

Related

  • Inheritance in PHP: A Simple Guide With Examples
  • A Guide to Constructor Chaining in Java
  • Achieving Inheritance in NoSQL Databases With Java Using Eclipse JNoSQL
  • HTTP-Based OOP, Inheritance, and Polymorphism

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!