Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "EclipseLink/UserGuide/MOXy/Type Level/Handling Inheritance"

m (Using MOXy Exentions)
m (Using MOXy Exentions: @XmlDescriminatorNode/@XmlDescrimintatorValue)
Line 229: Line 229:
 
You can use the '''@XmlDescriminatorNode''' and '''@XmlDescrimintatorValue''' MOXy extensions avaialable in EclipseLink 2.2 JAXB to represent inheritance. With these extensions, you can select the attribute to represent the subtype.
 
You can use the '''@XmlDescriminatorNode''' and '''@XmlDescrimintatorValue''' MOXy extensions avaialable in EclipseLink 2.2 JAXB to represent inheritance. With these extensions, you can select the attribute to represent the subtype.
  
 +
In this example an abstract super class ('''ContactInfo'') contains all types of contact information. The '''ContactInfo''' uses the '''@XmlDescriminatorNode''' annotation to specify the XML attribute ('''classifier''') to indicate the subtype.
  
 
+
'''Address''' and '''PhoneNumber''' are the concrete implementations of '''ContactInfo'''. The '''@XmlDescriminatorValue''' is used to override the default type name.
 
+
The model will contain an abstract super class for all types of contact information. We will use MOXy's @XmlDescriminatorNode annotation to specify the XML attribute we wish to use to indicate the appropriate subtype.
+
 
+
Address and PhoneNumber will be the concrete implementations of ContactInfo. By default the type name will be used with the discriminator node, we can override this by using @XmlDescriminatorValue.
+
 
+
 
+
 
+
  
 
<source lang="java">
 
<source lang="java">
Line 264: Line 258:
 
   
 
   
 
}
 
}
</source>
 
 
  
 
 
package blog.inheritance;
 
 
 
1
 
2
 
3
 
4
 
5
 
6
 
7
 
8
 
 
package blog.inheritance;
 
 
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue;
 
 
 
@XmlDiscriminatorValue("phone-number-classifier")
 
@XmlDiscriminatorValue("phone-number-classifier")
 
public class PhoneNumber extends ContactInfo {
 
public class PhoneNumber extends ContactInfo {
Line 290: Line 264:
 
}
 
}
  
The Customer object can have different types of contact info set on it, so the property will refer to the super class.
+
</source>
 
+
1
+
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
 
 
package blog.inheritance;
 
 
import javax.xml.bind.annotation.XmlRootElement;
 
 
@XmlRootElement
 
public class Customer {
 
 
    private ContactInfo contactInfo;
 
 
    public ContactInfo getContactInfo() {
 
        return contactInfo;
 
    }
 
 
    public void setContactInfo(ContactInfo contactInfo) {
 
        this.contactInfo = contactInfo;
 
    }
 
 
}
 
 
Java Model - jaxb.properties
 
 
In order to specify that we are using the MOXy JAXB implementation we need to put a file called jaxb.properties in with our Address class with the following entry:
 
  
 +
The''' Customer''' object can have different types of contact info set on it, so the property will refer to the super class.
 +
===jaxb.properties===
 +
To use the MOXy JAXB implementation, use a '''jaxb.properties''' file with the '''Address''' class that contains the following:
 +
<code>
 
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
 
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
 
+
</code>
 
+
Demo Code
+
  
 
We will use the following demo code to demonstrate the use of the descriminator node to represent inheritance.
 
We will use the following demo code to demonstrate the use of the descriminator node to represent inheritance.
  
1
+
<source lang="java">
2
+
3
+
4
+
5
+
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
 
 
 
package blog.inheritance;
 
package blog.inheritance;
Line 384: Line 299:
 
   
 
   
 
}
 
}
 
+
</source>
XML
+
  
 
The following is the resulting XML document.  Note that the Address object is marshalled to the contactInfo element with the classifier attribute containing the discriminator node value "address-classifier".
 
The following is the resulting XML document.  Note that the Address object is marshalled to the contactInfo element with the classifier attribute containing the discriminator node value "address-classifier".
  
 +
<source lang="xml">
  
1
 
2
 
3
 
4
 
5
 
 
 
<customer>
 
<customer>
 
   <contactInfo classifier="address-classifier">
 
   <contactInfo classifier="address-classifier">
Line 402: Line 311:
 
</customer>
 
</customer>
  
How does this All Work?
+
</source>
  
 
This is very similar to using the xsi:type attribute to represent the sub type.  However in this case we are not leveraging an XML schema concept.  This is not necessarily a bad thing, as there are legitimate use cases where this type of behaviour is required (check out this Stack Overflow post for an example).  It is also useful when you need to interact with XML binding tools with proprietary mechanisms for handling inheritance.
 
This is very similar to using the xsi:type attribute to represent the sub type.  However in this case we are not leveraging an XML schema concept.  This is not necessarily a bad thing, as there are legitimate use cases where this type of behaviour is required (check out this Stack Overflow post for an example).  It is also useful when you need to interact with XML binding tools with proprietary mechanisms for handling inheritance.

Revision as of 10:52, 24 March 2011

Handling Inheritance


Using xsi:type Attribute

You can use the xsi:type attribute to represent inheritance in JAXB.

In this example an abstract super class ('ContactInfo) contains all types of contact information. Address and PhoneNumber are the concrete implementations of ContactInfo.

package blog.inheritance;
 
public abstract class ContactInfo {
 
}
 
public class Address extends ContactInfo {
 
    private String street;
 
    public String getStreet() {
        return street;
    }
 
    public void setStreet(String street) {
        this.street = street;
    }
 
}
 
public class PhoneNumber extends ContactInfo {
 
}


Because the Customer object can have different types of contact information, its property refers to the superclass.

 
package blog.inheritance;
 
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement
public class Customer {
 
    private ContactInfo contactInfo;
 
    public ContactInfo getContactInfo() {
        return contactInfo;
    }
 
    public void setContactInfo(ContactInfo contactInfo) {
        this.contactInfo = contactInfo;
    }
 
}


In this example, the xsi:type attribute represents inheritance.

 
package blog.inheritance;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
 
public class Demo {
 
    public static void main(String[] args) throws Exception {
        Customer customer = new Customer();
        Address address = new Address();
        address.setStreet("1 A Street");
        customer.setContactInfo(address);
 
        JAXBContext jc = JAXBContext.newInstance(Customer.class, Address.class, PhoneNumber.class);
 
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }
 
}

The above sample code produces the following XML.

 
<customer>
    <contactInfo 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:type="address">
        <street>1 A Street</street>
    </contactInfo>
</customer>

Note the xsi:type attribute on the contactInfo element.


Using Substitution Groups

You can represent inheritance by using the element name with XML schema substitution groups.

In this example, the Java model contains an abstract superclass, ContactInfo for all types of contact information. Address and PhoneNumber are the concrete implementations of ContactInfo.

 
package blog.inheritance;
 
import javax.xml.bind.annotation.XmlRootElement;
 
public abstract class ContactInfo {
 
}
 
@XmlRootElement
public class Address extends ContactInfo {
 
    private String street;
 
    public String getStreet() {
        return street;
    }
 
    public void setStreet(String street) {
        this.street = street;
    }
 
}
 
@XmlRootElement
public class PhoneNumber extends ContactInfo {
 
}

Both Address and PhoneNumber use the @XmlRootElement annotation because the element name is used as the inheritance indicator.


Because the Customer object can have different types of contact information, its property refers to the superclass. The contactInfo property includes the @XmlElementRef annotation to indicate the value type will be derived from the element name (and namespace URI).

 
package blog.inheritance;
 
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
 
@XmlRootElement
public class Customer {
 
    private ContactInfo contactInfo;
 
    @XmlElementRef
    public ContactInfo getContactInfo() {
        return contactInfo;
    }
 
    public void setContactInfo(ContactInfo contactInfo) {
        this.contactInfo = contactInfo;
    }
 
}

In the following example, the xsi:type attribute represents inheritance.

 
package blog.inheritance;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
 
public class Demo {
 
    public static void main(String[] args) throws Exception {
        Customer customer = new Customer();
        Address address = new Address();
        address.setStreet("1 A Street");
        customer.setContactInfo(address);
 
        JAXBContext jc = JAXBContext.newInstance(Customer.class, Address.class, PhoneNumber.class);
 
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }
 
}

The above sample code produces the following XML.

<customer>
    <address>
        <street>1 A Street</street>
    </address>
</customer>

Note that the Address object is marshalled to the address element.







Using MOXy Exentions: @XmlDescriminatorNode/@XmlDescrimintatorValue

You can use the @XmlDescriminatorNode and @XmlDescrimintatorValue MOXy extensions avaialable in EclipseLink 2.2 JAXB to represent inheritance. With these extensions, you can select the attribute to represent the subtype.

In this example an abstract super class ('ContactInfo) contains all types of contact information. The ContactInfo uses the @XmlDescriminatorNode annotation to specify the XML attribute (classifier) to indicate the subtype.

Address and PhoneNumber are the concrete implementations of ContactInfo. The @XmlDescriminatorValue is used to override the default type name.

package blog.inheritance;
 
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode;
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue;
 
@XmlDiscriminatorNode("@classifier")
public abstract class ContactInfo {
 
}
 
@XmlDiscriminatorValue("address-classifier")
public class Address extends ContactInfo {
 
    private String street;
 
    public String getStreet() {
        return street;
    }
 
    public void setStreet(String street) {
        this.street = street;
    }
 
}
 
@XmlDiscriminatorValue("phone-number-classifier")
public class PhoneNumber extends ContactInfo {
 
}


The Customer object can have different types of contact info set on it, so the property will refer to the super class.

jaxb.properties

To use the MOXy JAXB implementation, use a jaxb.properties file with the Address class that contains the following: javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

We will use the following demo code to demonstrate the use of the descriminator node to represent inheritance.

 
package blog.inheritance;
 
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
 
public class Demo {
 
    public static void main(String[] args) throws Exception {
        Customer customer = new Customer();
        Address address = new Address();
        address.setStreet("1 A Street");
        customer.setContactInfo(address);
 
        JAXBContext jc = JAXBContext.newInstance(Customer.class, Address.class, PhoneNumber.class);
 
        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }
 
}

The following is the resulting XML document. Note that the Address object is marshalled to the contactInfo element with the classifier attribute containing the discriminator node value "address-classifier".

<customer>
   <contactInfo classifier="address-classifier">
      <street>1 A Street</street>
   </contactInfo>
</customer>

This is very similar to using the xsi:type attribute to represent the sub type. However in this case we are not leveraging an XML schema concept. This is not necessarily a bad thing, as there are legitimate use cases where this type of behaviour is required (check out this Stack Overflow post for an example). It is also useful when you need to interact with XML binding tools with proprietary mechanisms for handling inheritance.

Copyright © Eclipse Foundation, Inc. All Rights Reserved.