|
|
(15 intermediate revisions by the same user not shown) |
Line 1: |
Line 1: |
− | {{EclipseLink_UserGuide
| + | Please see http://www.eclipse.org/eclipselink/documentation/2.4/moxy/type_level003.htm |
− | |info=y
| + | |
− | |eclipselink=y
| + | |
− | |eclipselinktype=MOXy
| + | |
− | }}
| + | |
− | = Handling Inheritance =
| + | |
− | With EclipseLink JAXB MOXy, you can demonstrate inheritance in multiple ways:
| + | |
− | * [[#xsitype|xsi:Type Attribute]]
| + | |
− | * [[#substitution|Substitution Groups]]
| + | |
− | * [[#moxyextensions|MOXy Extension @XmlDescriminatorNode/@XmlDescrimintatorValue]]
| + | |
− | | + | |
− | | + | |
− | <span id="xsitype"></span>
| + | |
− | == 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'''.
| + | |
− | | + | |
− | <source lang="java">
| + | |
− | 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 {
| + | |
− |
| + | |
− | }
| + | |
− | | + | |
− | </source>
| + | |
− | | + | |
− | | + | |
− | Because the '''Customer''' object can have different types of contact information, its property refers to the superclass.
| + | |
− | | + | |
− | <source lang="java">
| + | |
− | 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;
| + | |
− | }
| + | |
− |
| + | |
− | }
| + | |
− | </source>
| + | |
− | | + | |
− | | + | |
− | | + | |
− | In this example, the '''xsi:type''' attribute represents inheritance.
| + | |
− | | + | |
− | <source lang="java">
| + | |
− | 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);
| + | |
− | }
| + | |
− |
| + | |
− | }
| + | |
− | </source>
| + | |
− | | + | |
− | The above sample code produces the following XML.
| + | |
− | <source lang="xml">
| + | |
− |
| + | |
− | <customer>
| + | |
− | <contactInfo
| + | |
− | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
| + | |
− | xsi:type="address">
| + | |
− | <street>1 A Street</street>
| + | |
− | </contactInfo>
| + | |
− | </customer>
| + | |
− | </source>
| + | |
− | Note the '''xsi:type''' attribute on the '''contactInfo''' element.
| + | |
− | | + | |
− | | + | |
− | <span id="substitution"></span>
| + | |
− | ==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'''.
| + | |
− | | + | |
− | <source lang="java">
| + | |
− |
| + | |
− | 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 {
| + | |
− |
| + | |
− | }
| + | |
− | | + | |
− | </source>
| + | |
− |
| + | |
− | 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).
| + | |
− | | + | |
− | <source lang="java">
| + | |
− | 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;
| + | |
− | }
| + | |
− |
| + | |
− | }
| + | |
− | | + | |
− | </source>
| + | |
− | | + | |
− | In the following example, the '''xsi:type''' attribute represents inheritance.
| + | |
− | | + | |
− | <source lang="java">
| + | |
− |
| + | |
− | 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);
| + | |
− | }
| + | |
− |
| + | |
− | }
| + | |
− | </source>
| + | |
− | | + | |
− | The above sample code produces the following XML.
| + | |
− | <source lang="xml">
| + | |
− | | + | |
− | <customer>
| + | |
− | <address>
| + | |
− | <street>1 A Street</street>
| + | |
− | </address>
| + | |
− | </customer>
| + | |
− | | + | |
− | </source>
| + | |
− | | + | |
− | Note that the '''Address''' object is marshalled to the '''address''' element.
| + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | | + | |
− | <span id="moxyextensions"></span>
| + | |
− | ==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.
| + | |
− | | + | |
− | <source lang="java">
| + | |
− | 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 {
| + | |
− |
| + | |
− | }
| + | |
− | | + | |
− | </source>
| + | |
− |
| + | |
− | | + | |
− | 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
| + | |
− | </code>
| + | |
− | | + | |
− | In the following example, the descriminator represents inheritance.
| + | |
− | <source lang="java">
| + | |
− |
| + | |
− | 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);
| + | |
− | }
| + | |
− |
| + | |
− | }
| + | |
− | </source>
| + | |
− | | + | |
− | The above sample produces the following XML.
| + | |
− | | + | |
− | <source lang="xml">
| + | |
− | | + | |
− | <customer>
| + | |
− | <contactInfo classifier="address-classifier">
| + | |
− | <street>1 A Street</street>
| + | |
− | </contactInfo>
| + | |
− | </customer>
| + | |
− | | + | |
− | </source>
| + | |
− | | + | |
− | Notice that '''Address''''is marshalled to the '''contactInfo''' element. Its '''classifier''' attribute contains the discriminator node value '''address-classifier'''.
| + | |