Skip to main content
Jump to: navigation, search

EclipseLink/DesignDocs/293925/MOXyExtensions/XMLCompositeMapping

XMLCompositeObjectMapping

Requirements

Provide support for XML composite object mapping configuration via XML metadata file.

The following structures are to be extended to support XML composite object mapping configuration:

The following should be configurable:

Design

Basic XML composite object mapping support

We will use the xml-element structure to support composite mappings. For example, the following XML metadata snippet would be used to setup a composite mapping for homeAddress, given the following object model:

package org.example;
 
public Employee {
    public Address homeAddress;
}
 
package org.example;
 
public Address {
    public String street;
    public String city;
    public String prov;
    public String postal;
}

Xml metadata snippet

<xml-element java-attribute="homeAddress" name="home-address" />

Equivalent annotations

@javax.xml.bind.annotation.XmlElement(name="home-address")
public Address homeAddress

Self Mappings

In the case above a sample instance document would look like to following:

<employee>
    <address>
        <street>Some St.</street>
        <city>Ottawa</city>
        <prov>ON</prov>
        <postal>K1P1A4</postal>
    </address>
</employee>

If, however, the address sub-elements (street, city, etc.) were to be mapped directly into the employee instead of having the address grouping element, a 'self' mapping could be used. Self composite mappings are configured by using the xml-path '.' as follows:

Xml metadata snippet

<xml-element java-attribute="homeAddress" xml-path="." />

And the following instance document would be valid:

<employee>
    <street>Some St.</street>
    <city>Ottawa</city>
    <prov>ON</prov>
    <postal>K1P1A4</postal>
</employee>

Equivalent annotations

@javax.xml.bind.annotation.XmlElement
@org.eclipse.persistence.oxm.annotations.XmlPath(".")
public Address homeAddress

Path-based mapping support

We will support path-based mappings on xml-element via xml-path attribute. If xml-path is present, it is assumed to contain the entire XPath, hence the name and namespace attributes - if set - will be ignored, as well as any xml-element-wrapper declarations. An example of configuring a path-based XML composite mapping can be found below.

Positional Mappings

Positional mappings will be supported on xml-element. An example of configuring a positional XML composite mapping can be found below.

Read Only

Read only will be supported via boolean attribute on xml-element. An example of configuring a read only XML composite mapping can be found below.

Write Only

Write only will be supported via boolean attribute on xml-element. An example of configuring a write only XML composite mapping can be found below.

Null Poilcy

Null policy will be supported via sub-element on xml-element. The proposed schema modifications for the global null policy elements/complex types can be found here. An example of configuring a null policy on an XML composite mapping can be found below.

Get/Set Method Names

The get/set method names on xml-element will be configurable via sub-element. An example of configuring the accessor methods on a XML composite mapping can be found below, and proposed schema changes can be found here.

Example

The following example will demonstrate how to configure a number of XML composite object mappings via XML metadata.

org.example.Employee.java

package org.example;
 
public class Employee {
    public Address homeAddress;
    public Address workAddress;
    public Address alternateAddress;
    public Phone phone1;
    public Phone phone2;
    public Foo foo;
    public Phone privatePhone;
    public Department department;
    public Department aDept;
 
    public Department getDepartment() {
        wasGetCalled = true;
        return department;
    }
 
    public void setDepartment(Department department) {
        wasSetCalled = true;
        this.department = department;
    }
 
    Department getADept() { 
        return aDept; 
    }
 
    void setADept(Department dept) {
        aDept = dept; 
    }
}

org.example.Address.java

package org.example;
 
public class Address {
    public String city;
    public String street;
    public String province;
    public String postalCode;
}

org.example.Phone.java

package org.example;
 
public class Phone {
    public String number;
}

org.example.Department.java

package org.example;
 
public class Department {
    public int deptId;
    public String deptName;
}

org.example.Foo.java

package org.example;
 
public class Foo {
    public String foodata;
}

Deployment XML

   <class-mapping-descriptors>
      <class-mapping-descriptor xsi:type="xml-class-mapping-descriptor">
         <class>org.example.Employee</class>
         <alias>Employee</alias>
         <attribute-mappings>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>foo</attribute-name>
               <field name="." xsi:type="node"/>
            </attribute-mapping>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>homeAddress</attribute-name>
               <field name="info/contact-info/home-address" xsi:type="node"/>
            </attribute-mapping>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>workAddress</attribute-name>
               <field name="info/contact-info/work-address" xsi:type="node"/>
            </attribute-mapping>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>alternateAddress</attribute-name>
               <read-only>true</read-only>
               <field name="info/contact-info/alternate-address" xsi:type="node"/>
            </attribute-mapping>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>phone1</attribute-name>
               <field name="info/contact-info/phone[1]" xsi:type="node"/>
            </attribute-mapping>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>phone2</attribute-name>
               <field name="info/contact-info/phone[2]" xsi:type="node"/>
            </attribute-mapping>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>privatePhone</attribute-name>
               <field name="private-phone" xsi:type="node"/>
            </attribute-mapping>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>department</attribute-name>
               <get-method>getDepartment</get-method>
               <set-method>setDepartment</set-method>
               <field name="." xsi:type="node"/>
            </attribute-mapping>
            <attribute-mapping xsi:type="xml-composite-object-mapping">
               <attribute-name>aDept</attribute-name>
               <get-method>getADept</get-method>
               <set-method>setADept</set-method>
               <field name="a-dept" xsi:type="node"/>
               <null-policy xsi:type="null-policy">
                  <null-representation-for-xml>EMPTY_NODE</null-representation-for-xml>
               </null-policy>
            </attribute-mapping>
         </attribute-mappings>
         <default-root-element>employee</default-root-element>
         <default-root-element-field name="employee"/>
      </class-mapping-descriptor>
      <class-mapping-descriptor xsi:type="xml-class-mapping-descriptor">
         <class>org.example.Foo</class>
         <alias>Foo</alias>
         <attribute-mappings>
            <attribute-mapping xsi:type="xml-direct-mapping">
               <attribute-name>foodata</attribute-name>
               <field name="@foodata" xsi:type="node"/>
            </attribute-mapping>
         </attribute-mappings>
         <default-root-element>foo</default-root-element>
         <default-root-element-field name="foo"/>
      </class-mapping-descriptor>
   </class-mapping-descriptors>

XML Instance Document (read)

<?xml version="1.0" encoding="UTF-8"?>
<employee foodata="myfoo">
    <info>
        <contact-info>
            <home-address>
                <city>Kanata</city>
                <street>66 Lakview Drive</street>
                <province>ON</province>
                <postalCode>K2M2K7</postalCode>
            </home-address>
            <work-address>
                <city>Ottawa</city>
                <street>45 O'Connor St.</street>
                <province>ON</province>
                <postalCode>K1P1A4</postalCode>
            </work-address>
            <alt-address>
                <city>Austin</city>
            </alt-address>
            <phone>
                <number>613.288.0001</number>
            </phone>
            <phone>
                <number>613.288.0002</number>
            </phone>
            <phone>
                <number>613.288.0003</number>
            </phone>
        </contact-info>
    </info>
    <private-phone>
        <number>000.000.0000</number>
    </private-phone>
    <deptId>101</deptId>
    <deptName>Sanitation</deptName>
</employee>

XML Instance Document (write)

<?xml version="1.0" encoding="UTF-8"?>
<employee foodata="myfoo">
    <info>
        <contact-info>
            <home-address>
                <city>Kanata</city>
                <street>66 Lakview Drive</street>
                <province>ON</province>
                <postalCode>K2M2K7</postalCode>
            </home-address>
            <work-address>
                <city>Ottawa</city>
                <street>45 O'Connor St.</street>
                <province>ON</province>
                <postalCode>K1P1A4</postalCode>
            </work-address>
            <phone>
                <number>613.288.0001</number>
            </phone>
            <phone>
                <number>613.288.0002</number>
            </phone>
        </contact-info>
    </info>
    <private-phone>
        <number>000.000.0000</number>
    </private-phone>
    <deptId>101</deptId>
    <deptName>Sanitation</deptName>
    <a-dept />
</employee>

org/example/eclipselink-oxm.xml

This XML file demonstrates configuring XML composite mappings on the "org.example.Employee" class.

<?xml version="1.0" encoding="US-ASCII"?>
<xml-bindings xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema">
    <java-types>
        <java-type name="org.example.Employee" xml-accessor-type="FIELD">
            <xml-root-element name="employee" />
            <java-attributes>
                <xml-element java-attribute="foo" xml-path="." />
                <xml-element java-attribute="homeAddress" xml-path="info/contact-info/home-address" />
                <xml-element java-attribute="workAddress" xml-path="info/contact-info/work-address" />
                <xml-element java-attribute="alternateAddress" xml-path="info/contact-info/alt-address" read-only="true" />
                <xml-element java-attribute="phone1" xml-path="info/contact-info/phone[1]" />
                <xml-element java-attribute="phone2" xml-path="info/contact-info/phone[2]" />
                <xml-element java-attribute="privatePhone" name="private-phone" write-only="true" />
                <xml-element java-attribute="department" xml-path=".">
                    <xml-access-methods get-method="getDepartment" set-method="setDepartment" />
                </xml-element>
                <xml-element java-attribute="aDept" name="a-dept">
                    <xml-access-methods get-method="getADept" set-method="setADept" />
                    <xml-null-policy xsi-nil-represents-null="false" empty-node-represents-null="false" null-representation-for-xml="EMPTY_NODE" is-set-performed-for-absent-node="true" />
                </xml-element>
            </java-attributes>
        </java-type>
        <java-type name="org.example.Foo" xml-accessor-type="FIELD">
            <java-attributes>
                <xml-attribute java-attribute="foodata" />
            </java-attributes>        
        </java-type>
    </java-types>
</xml-bindings>

Open Issues

This section lists the open issues that are still pending that must be decided prior to fully implementing this project's requirements.

Issue# Owner Description/Notes

Decisions

This section lists decisions made. These are intended to document the resolution of open issues or constraints added to the project that are important.

Issue# Description/Notes Decision

Future Considerations

During the research for this project the following items were identified as out of scope but are captured here as potential future enhancements. If agreed upon during the review process these should be logged in the bug system.

Copyright © Eclipse Foundation, Inc. All Rights Reserved.