EclipseLink/DesignDocs/317962/Phase2.1

From Eclipsepedia

Jump to: navigation, search

Contents

Phase 2 - Additional MOXy annotation/xml metadata support

This phase of development involves providing additional MOXy annotations and XML metadata support that will allow configuration similar to that of deployment XML

Annotations/XML Metadata

The following MOXy annotations/XML metadata will be targeted in this phase:

MOXy Annotation XML Metadata Tag Package Type Field Method
XmlProperties xml-properties X X X
XmlProperty xml-property X X X
XmlTransformation xml-transformation X X
XmlReadTransformer xml-read-transformer X X
XmlWriteTransformer xml-write-transformer X X
XmlClassExtractor xml-class-extractor X

XmlProperties

Purpose

Descriptors and mappings can contain a Map of properties. @XmlProperties and xml-properties will be used as a wrapper for one or more property entries. See below for additional information and examples of use.

XmlProperty

Purpose

Provides a means to set a property on a mapping or descriptor. Any annotations set on a property will be completely replaced by XML. Any annotations set on a type will be merged with XML, with XML taking precedence in the case of a conflict.

Java Metadata

@XmlProperties

The following is the proposed source code for the XmlProperties annotation:

@Target({METHOD, FIELD, TYPE})
@Retention(RUNTIME)
public @interface XmlProperties {
    XmlProperty[] value();
}

@XmlProperty

The following is the proposed source code for the XmlProperty annotation:

@Target({METHOD, FIELD, TYPE})
@Retention(RUNTIME)
public @interface XmlProperty {
    /**
     * Property name.
     */ 
    String name();
 
    /**
     * String representation of Property value,
     * converted to an instance of valueType.
     */ 
    String value();
 
    /**
     * Property value type.
     * The value converted to valueType by ConversionManager.
     * If specified must be a simple type that could be handled by ConversionManager: 
     * numerical, boolean, temporal.  
     */ 
    Class valueType() default String.class;

XML Metadata

xml-properties

The xml-properties metadata tag will be used as a grouping element for one or more xml-property elements.

xml-property

The xml-property metadata tag will be used to configure a property.

XML Schema

Since there can be multiple properties on a mapping or descriptor, and <xs:all> doesn't allow maxOccurs="unbounded", we will wrap xml-property in xml-properties. Following are the proposed schema changes:

<xs:element name="xml-properties" type="xml-properties" />
<xs:complexType name="xml-properties">
    <xs:sequence>
        <xs:element name="xml-property" minOccurs="0" maxOccurs="unbounded" >
            <xs:complexType>
                <xs:attribute name="name" type="xs:string" use="required" />
                <xs:attribute name="value" type="xs:string" use="required" />
                <xs:attribute name="value-type" type="xs:string" default="java.lang.String" />
            </xs:complexType>
        </xs:element>
    </xs:sequence>
</xs:complexType>

An element ref to the new global xml-properties element will be added to the following:

  • java-type
  • xml-any-attribute
  • xml-attribute
  • xml-any-element
  • xml-element
  • xml-elements
  • xml-element-ref
  • xml-element-refs
  • xml-inverse-reference
  • xml-value
  • xml-transformation

Example: type-level property

The following example will demonstrate how a type-level property can be applied.

Setting xml-property on a type via EclipseLink XML metadata can be accomplished as follows:

<java-type name="org.example.Employee">
    <xml-properties>
        <xml-property name="identifier" value="101" value-type="java.lang.Integer" />
        <xml-property name="isTrue" value="false" value-type="java.lang.Boolean" />
    </xml-properties>
</java-type>

Setting @XmlProperty on a type via annotations can be accomplished as follows:

org.example.Employee.java
@XmlProperties({@XmlProperty(name="identifier", value="101", valueType=Integer.class), 
                @XmlProperty(name="isTrue", value="false", valueType=Boolean.class)})
public class Employee {
   ...
}

Example: property-level property

The following example will demonstrate how a property-level property can be applied.

Setting xml-property on a property via EclipseLink XML metadata can be accomplished as follows:

<java-type name="org.example.Employee">
    <java-attributes>
        <xml-element java-attribute="myelement">
            <xml-properties>
                <xml-property name="isAttribute" value="false" value-type="java.lang.Boolean" />
                <xml-property name="comment" value="this is an element" />
            </xml-properties>
        </xml-element>
    </java-attributes>
</java-type>

Setting @XmlProperty on a property via annotations can be accomplished as follows:

org.example.Employee.java
public class Employee {
 
  @XmlProperties({@XmlProperty(name="isAttribute", value="false", valueType=Boolean.class),
                  @XmlProperty(name="comment", value="this is an element")}
  public String myelement;
}

XmlTransformation

Purpose

Provides a means to configure an org.eclipse.persistence.oxm.mappings.XMLTransformationMapping. Transformation mappings are used to create a custom mapping where one or more XML nodes can be used to create the object to be stored in a Java class's attribute.

Java Metadata

@XmlTransformation

Here is the proposed source code for the XmlTransformation annotation:

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface XmlTransformation {
    /**
     * (Optional) The optional element is a hint as to whether the value
     *  of the field or property may be null. It is disregarded
     *  for primitive types, which are considered non-optional.
     */
    boolean optional() default true;

@XmlReadTransformer

Here is the proposed source code for the XmlReadTransformer annotation:

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface XmlReadTransformer {
 
    /**
     * User-defined class that must implement the 
     * org.eclipse.persistence.mappings.transformers.AttributeTransformer 
     * interface. The class will be instantiated, its buildAttributeValue will 
     * be used to create the value to be assigned to the attribute.
     * Either transformerClass or method must be specified, but not both.
     */ 
    Class<? extends AttributeTransformer> transformerClass() default AttributeTransformer.class;
 
    /**
     * The mapped class must have a method with this name which returns a value 
     * to be assigned to the attribute (not assigns the value to the attribute).
     * Either transformerClass or method must be specified, but not both.
     */ 
    String method() default "";
}

@XmlWriteTransformer

Here is the proposed source code for the XmlWriteTransformer annotation:

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface XmlWriteTransformer {
 
    /**
     * User-defined class that must implement the
     * org.eclipse.persistence.mappings.transformers.FieldTransformer interface.
     * The class will be instantiated, its buildFieldValue will be used to 
     * create the value to be written into XML document.
     * Either transformerClass or method must be specified, but not both.
     */ 
    Class<? extends FieldTransformer> transformerClass() default FieldTransformer.class;
 
    /**
     * The mapped class must have a method with this name which returns a value 
     * to be written into the XML document.
     * The method may require an XmlTransient annotation to avoid being mapped as 
     * an XmlElement  by default.
     * Either transformerClass or method must be specified, but not both.
     */ 
    String method() default "";
 
    /**
     * Specify here the XPath into which the value should be written.
     * The only case when this could be skipped is if a single WriteTransformer
     * annotates an attribute - the attribute's name will be
     * used as an element name.
     */ 
    String xmlPath();
}

@XmlWriteTransformers

Here is the proposed source code for the XmlWriteTransformers annotation:

@Target({METHOD, FIELD})
@Retention(RUNTIME)
public @interface XmlWriteTransformers {
 
    XmlWriteTransformer[] value() default {};
}

XML Metadata

xml-transformation

The xml-transformation metadata tag will be used to configure a transformation.

xml-read-transformer

Defines transformation of node(s) value(s) into an attribute value. This corresponds to an attribute transformer on the XmlTransformationMapping.

  • method
    • The mapped class must have a method with this name which returns a value to be assigned to the attribute.
    • The method should have one of the following signatures:
      • myMethod(Record)
      • myMethod(Record, AbstractSession)
      • myMethod(Record, Session)
  • transformer-class
    • This is a user-defined class that must implement the org.eclipse.persistence.mappings.transformers.AttributeTransformer interface. The class will be instantiated, and its buildAttributeValue(Record, Object, Session) method will be used to create the value to be assigned to the attribute.

Note that either a method or transformer-class should be set, but not both. In the event that both/neither are set an exception will be thrown.

xml-write-transformer

Defines transformation of the attribute value to a single node value. This corresponds to a field transformer on the XmlTransformationMapping.

  • method
    • The mapped class must have a method with this name which returns a value to be assigned to the attribute.
    • The method should have one of the following signatures:
      • myMethod()
      • myMethod(AbstractSession)
      • myMethod(Session)
  • transformer-class
    • This is a user-defined class that must implement the org.eclipse.persistence.mappings.transformers.FieldTransformer interface. The class will be instantiated, and its buildFieldValue(Object, String, Session) will be used to create the value to be written into the node.
  • xml-path
    • Identifies the node into which the value should be written. This should be set in all cases.

Note that either a method or transformer-class should be set, but not both. In the event that both/neither are set an exception will be thrown.

XML Schema

Following is the proposed schema structure for xml-transformation:

<xs:element name="xml-transformation" substitutionGroup="java-attribute">
    <xs:complexType>
        <xs:complexContent>
            <xs:extension base="java-attribute">
                <xs:sequence>
                    <xs:element name="xml-access-methods" type="xml-access-methods" minOccurs="0"/>
                    <xs:element ref="xml-properties" minOccurs="0"/>
                    <xs:element name="xml-read-transformer">
                        <xs:complexType>
                            <xs:attribute name="method" type="xs:string" />
                            <xs:attribute name="transformer-class" type="xs:string" />
                        </xs:complexType>
                    </xs:element>
                    <xs:element name="xml-write-transformer" minOccurs="0" maxOccurs="unbounded">
                        <xs:complexType>
                            <xs:attribute name="method" type="xs:string" />
                            <xs:attribute name="xml-path" type="xs:string" />
                            <xs:attribute name="transformer-class" type="xs:string" />
                        </xs:complexType>
                    </xs:element>
                </xs:sequence>
                <xs:attribute name="optional" type="xs:boolean" default="false"/>
            </xs:extension>
        </xs:complexContent>
    </xs:complexType>
</xs:element>

Example

The following example will demonstrate how a transformation can be applied.

Setting xml-transformation via EclipseLink XML metadata can be accomplished as follows:

<java-type name="org.example.Employee">
    <java-attributes>
        <xml-transformation java-attribute="normalHours" optional="true">
            <xml-access-methods get-method="getNormalHours" set-method="setNormalHours" />
            <xml-read-transformer transformer-class="org.example.NormalHoursTransformer" />
            <xml-write-transformer xml-path="normal-hours/start-time/text()" transformer-class="org.example.StartTimeTransformer"/>
            <xml-write-transformer xml-path="normal-hours/end-time/text()" transformer-class="org.example.EndTimeTransformer"/>
        </xml-transformation>
    </java-attributes>
</java-type>

Setting the @XmlTransformation via annotations can be accomplished as follows:

org.example.Employee.java
@XmlRootElement(name="employee")
public class Employee {
    public String name;
 
    @XmlTransformation
    @XmlReadTransformer(transformerClass = NormalHoursTransformer.class)
    @XmlWriteTransformers({
        @XmlWriteTransformer(transformerClass = StartTimeTransformer.class, xpath= "normal-hours/start-time/text()"),
        @XmlWriteTransformer(transformerClass = EndTimeTransformer.class, xpath="normal-hours/end-time/text()")
    })
    public String[] normalHours;

XmlClassExtractor

Purpose

A class extractor provides a means for complex inheritance support. A ClassExtractor instance is registered with the descriptor to override the default inheritance mechanism. This allows for a user defined class indicator in place of providing an explicit class indicator field. The instance registered must extend the org.eclipse.persistence.descriptors.ClassExtractor class and implement the extractClassFromRow(Record, Session) method; this method is used to determine which class to instantiate when unmarshalling.

Java Metadata

@XmlClassExtractor

The following is the proposed source code for the XmlClassExtractor annotation:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface XmlClassExtractor {
    /**
     * (Required) Defines the name of the class extractor that should be 
     * applied to this entity's descriptor.
     */
    Class value(); 
}

XML Metadata

xml-class-extractor

The class extractor can be set via XML metadata via the xml-class-extractor tag.

XML Schema

Following is the proposed schema structure for xml-class-extractor - a global element/complex type pair will be added, and a ref will be added to java-type:

<xs:element name="xml-class-extractor" type="xml-class-extractor" />
<xs:complexType name="xml-class-extractor">
    <xs:attribute name="class" type="xs:string" use="required"/>
</xs:complexType>

Example

The following example will demonstrate how a class extractor can be applied.

Setting xml-class-extractor via EclipseLink XML metadata can be accomplished as follows:

<java-type name="org.example.Person">
    <xml-class-extractor class="org.example.MyClassExtractor" />
</java-type>

Setting the Class Extractor via Annotations would be accomplished as follows: org.example.Person.java

package org.example;
 
@XmlClassExtractor(MyClassExtactor.class)
class Person {
    String name;
}
org.example.Employee.java
package org.example;
 
class Employee extends Person {
    String id;
}
org.example.MyClassExtractor.java
package org.example;
 
class MyClassExtractor extends org.eclipse.persistence.descriptors.ClassExtractor {
    /**
     * This method simply returns Employee.class.  Typically, the class to be 
     * returned would be based on the given Record.
     */
    public Class extractClassFromRow(Record databaseRow, Session session) {
        return Employee.class;
    }
}

Testing

This section identifies the test package(s) for each feature outlined on this page.

XML Metadata

XML Metadata Package
xml-properties org.eclipse.persistence.testing.jaxb.externalizedmetadata.mappings.direct
xml-property org.eclipse.persistence.testing.jaxb.externalizedmetadata.mappings.direct
xml-transformation org.eclipse.persistence.testing.jaxb.externalizedmetadata.xmltransformation
xml-class-extractor org.eclipse.persistence.testing.jaxb.externalizedmetadata.xmlclassextractor

Annotations

Annotation Package
XmlProperties org.eclipse.persistence.testing.jaxb.annotations.xmlproperties
XmlProperty org.eclipse.persstence.testing.jaxb.annotations.xmlproperties
XmlTransformation org.eclipse.persistence.testing.jaxb.annotations.xmltransformation
XmlClassExtractor org.eclipse.persistence.testing.jaxb.annotations.xmlclassextractor

Open Issues

This section lists open issues.

Issue# Description/Notes
1 Should the xml-path attribute be required on xml-write-transformer? The only case where one isn't required is in the case of a single xml-write-transfomer; in this case we could use the schemaName that is set on the associated Property.

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.

Decision# Description/Notes Decision
1 xml-class-extraction-method We will not provide support for setting a class extraction method name on the InheritancePolicy. Please refer to this bug for additional information.
2 xml-transformation It was decided not to support several properties from the jpa version of transformation as they don't apply to xml-transformation. The following properties were removed: name, mutable, access-type and attribute-type