June 1, 2011

Ignoring Inheritance with @XmlTransient

In previous articles I have covered how to map inheritance relationships in JAXB and EclipseLink MOXy.  In this example I will describe how to remove an inheritance relationship in JAXB by leveraging @XmlTransient at the type level.


Java Model

Base

In this example we want all of our domain objects to have an id property.  We will accomplish this by having all of our domain objects extend the same base class (Base). Since this base class is not relevant to the domain model we will tell JAXB to ignore it by marking it @XmlTransient.

package blog.inheritance.xmltransient;

import javax.xml.bind.annotation.XmlTransient;

@XmlTransient
public abstract class Base {

    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

}

Customer

Since the parent class has been marked @XmlTransient the id property will be treated as part of the child classes.  In the Customer class we will demonstrate this by including the id property in the propOrder specified on @XmlType.

package blog.inheritance.xmltransient;

import java.util.List;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

@XmlRootElement
@XmlType(propOrder={"id", "name", "address", "phoneNumbers"})
public class Customer extends Base {

    private String name;
    private Address address;
    private List<PhoneNumber> phoneNumbers;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

    @XmlElement(name="phone-number")
    public List<PhoneNumber> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setPhoneNumbers(List<PhoneNumber> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

}

Address

package blog.inheritance.xmltransient;

public class Address extends Base {

    private String street;

    public String getStreet() {
        return street;
    }

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

}

PhoneNumber

package blog.inheritance.xmltransient;

public class PhoneNumber extends Base {

    private String number;

    public String getNumber() {
        return number;
    }

    public void setNumber(String number) {
        this.number = number;
    }

}


Demo Code

Below is the demo code that can be used to run this example:

package blog.inheritance.xmltransient;

import java.io.File;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Customer customer = (Customer) unmarshaller.unmarshal(new File("input.xml"));

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

}

XML (input.xml)

In the XML you will notice that there are no inheritance indicators present.  The properties of the base class are simply treated as properties of the respective subclasses:

<?xml version="1.0" encoding="UTF-8"?>
<customer>
   <id>12</id>
   <name>Jane Doe</name>
   <address>
      <id>34</id>
      <street>1 A Street</street>
   </address>
   <phone-number>
      <id>45</id>
      <number>555-1111</number>
   </phone-number>
   <phone-number>
      <id>67</id>
      <number>555-2222</number>
   </phone-number>
</customer>

Further Reading

If you enjoyed this post you may also be interested in:

4 comments:

  1. Is it possible to do this with inherited interfaces, too?

    ReplyDelete
  2. You may find the following useful when using JAXB with interfaces:
    - JAXB and Interface Fronted Models

    -Blaise

    ReplyDelete
  3. Hi Blaise, thanks for the post.
    I'm trying to do exactly what you are describing here but the propOrder is throwing an exception:

    com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
    Property id appears in @XmlType.propOrder, but no such property exists. Maybe you meant hint?
    this problem is related to the following location:
    at com.domain.model.ChildModel

    The id is declared in the parent which is also annotated with XmlTransient. However, when I try to marshall the class it fails.

    Any ideas?

    Thanks,
    Ale

    ReplyDelete
    Replies
    1. Hi Ale,

      If you are using public (default) or property access, then the string you put in the propOrder is based on the accessor methods and not the field name. What is the get method that corresponds to the id field?

      -Blaise

      Delete