Jump to: navigation, search

EclipseLink/Development/DesignDocs/JPA XML Metadata Extensions

< EclipseLink‎ | Development‎ | DesignDocs
Revision as of 20:02, 10 March 2014 by Jesse.Weinstein.clinicomp.com (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Contents

Design Specification: JPA XML metadata extensions

JBS: This document is in the wrong location, should be moved to be under, http://wiki.eclipse.org/EclipseLink/DesignDocs. Also add link to it from design docs.

Document History

Date Author Version Description
2007-09-25 Guy Pelletier Initial Draft
2007-09-26 James Sutherland Comments

Goals

The goal of this design spec is to expose some features from EclipseLink that are currently not available through the use of JPA xml metadata. The features that will be exposed in this document already have their annotation counterparts implemented in the current version of EclipseLink. This document assumes familiarity with those annotations and will focus mainly on the XML extension portions. That is, in most cases, internal processing and design remains as already defined for the equivalent annotations. This document will discuss only those portions that will be required to be implemented or addressed as a result of introducing the new xml elements.

The new xml configurations will be added to the eclipse_orm_1_0.xsd file. This file will be a copy of the latest JPA orm.xml file plus the newly created xml elements.

Also note, the new features exposed by this design spec are by no means the end all of features available from EclipseLink. It is merely a set that collectively has been agreed upon as most important to expose in this release. The ultimate goal remains to completely replace the existing EclipseLink deployment project with the configuration of annotations and/or XML.

ORM file

The new orm file (eclipse_orm_1_0.xsd) will need to be hosted somewhere. Where?

  <entity-mappings version="1.0" xmlns="http://????? " xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://????? eclipse_orm_1_0.xsd">

Package

  • New classes will be added to their respectful metadata directory under the xml package. E.G. XML converter metadata classes should be added under the org.eclipse.persistence.internal.jpa.metadata.converters.xml. This will be outlined with each new xml element discussed in this document.

Converters

The following converter complex types will be added (converter, type-converter, object-type-converter, struct-converter) and there usage is specified through the convert attribute on those mapping elements that support using a converter. The following converter elements,

  <xsd:element name="converter" type="orm:converter" minOccurs="0" maxOccurs="unbounded"/>
  <xsd:element name="type-converter" type="orm:type-converter" minOccurs="0" maxOccurs="unbounded"/>
  <xsd:element name="object-type-converter" type="orm:object-type-converter" minOccurs="0" maxOccurs="unbounded"/>
  <xsd:element name="struct-converter" type="orm:struct-converter" minOccurs="0" maxOccurs="unbounded"/>

will be available from the following complex-types:

  • entity-mappings
  • entity
  • mapped-superclass
  • JBS: also embeddable

The new convert attribute,

  <xsd:attribute name="convert" type="xsd:string"/>

will be added to the following complex types:

  • basic
  • basic-map
  • basic-collection
  • JBS: also id, version

converter

The converter complex type will be added and is used to specify a custom converter for modification of the data value(s) during the reading and writing of a mapped attribute.

  <xsd:complexType name="converter">
    <xsd:annotation>
      <xsd:documentation>

        @Target({TYPE, METHOD, FIELD})
        @Retention(RUNTIME)
        public @interface Converter {
          /**
           * (Required) Name this converter. The name should be unique
           * across the whole persistence unit.
           */
          String name();

          /**
           * (Required) The converter class to be used. This class must implement 
           * the org.eclipse.persistence.mappings.converters.Converter interface.
           */
          Class converterClass(); 
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="name" type="xsd:string" use="required"/>
    <xsd:attribute name="converter-class" type="xsd:string" use="required"/>
  </xsd:complexType>

Example

  <converter name="gender" converter-class="my.gender.converter"/>

Design and processing

  • Build new org.eclipse.persistence.internal.jpa.metadata.converters.xml.XMLConverter class that extends org.eclipse.persistence.internal.jpa.metadata.MetadataConverter. Its only responsibility will be to override the metadata that is processed.
  • Processing is currently defined in the org.eclipse.persistence.internal.jpa.metadata.converters.MetadataConverter.

type-converter

The type-converter complex type will be added and is used to specify an org.eclipse.persistence.mappings.converters.TypeConversionConverter for modification of the data value(s) during the reading and writing of a mapped attribute

  <xsd:complexType name="type-converter">
    <xsd:annotation>
      <xsd:documentation>

        @Target({TYPE, METHOD, FIELD})
        @Retention(RUNTIME)
        public @interface TypeConverter {
          /**
           * (Required) Name this converter. The name should be unique
           * across the whole persistence unit.
           */
           String name();

          /**
           * (Optional) Specify the type stored on the database. The
           * default is inferred from the type of the persistence field 
           * or property.
           */
          Class dataType() default void.class;

          /**
           * (Optional) Specify the type stored on the entity. The
           * default is inferred from the type of the persistent field 
           * or property.
           */
          Class objectType() default void.class;
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="name" type="xsd:string" use="required"/>
    <xsd:attribute name="data-type" type="xsd:string"/>
    <xsd:attribute name="object-type" type="xsd:string"/>
  </xsd:complexType>

Example

  <type-converter name="doubleToFloat" data-type="java.lang.Double" object-type="java.lang.Float"/>

Design and processing

  • Build new org.eclipse.persistence.internal.jpa.metadata.converters.xml.XMLTypeConverter class that extends org.eclipse.persistence.internal.jpa.metadata.converters.MetadataTypeConverter. Its only responsibility will be to override the metadata that is processed.
  • Processing is currently defined in the org.eclipse.persistence.internal.jpa.metadata.converters.MetadataTypeConverter.

object-type-converter

The object-type-converter complex type (extends the type-converter complex type) will be added and is used to specify an org.eclipse.persistence.mappings.converters.ObjectTypeConverter that converts a fixed number of database data value(s) to Java object value(s) during the reading and writing of a mapped attribute.

  <xsd:complexType name="object-type-converter">
    <xsd:complexContent>	
      <xsd:extension base=type-converter>
        <xsd:annotation>
          <xsd:documentation>

            @Target({TYPE, METHOD, FIELD})
            @Retention(RUNTIME)
            public @interface ObjectTypeConverter {
              /**
               * (Required) Name this converter. The name should be unique
               * across the whole persistence unit.
               */
              String name();

              /**
               * (Optional) Specify the type stored on the database. The
               * default is inferred from the type of the persistence
               * field or property.
               */
              Class dataType() default void.class;

              /**
               * (Optional) Specify the type stored on the entity. The
               * default is inferred from the type of the persistent 
               * field or property.
               */
              Class objectType() default void.class;

              /**
               * (Required) Specify the conversion values to be used 
               * with the object converter.
               */
              ConversionValue[] conversionValues();

              /**
               * (Optional) Specify a default object value. Used for 
               * legacy data if the data value is missing.
               */
              String defaultObjectValue() default "";
            }

          </xsd:documentation>
        </xsd:annotation>
        <xsd:sequence>
          <xsd:element name="conversion-value" type="orm:conversion-value" minOccurs="1" maxOccurs=unbounded/>
          <xsd:element name="default-object-value" type="xsd:string" minOccurs="0"/>
        </xsd:sequence>
      </xsd:entension>
    </xsd:complexContent>
  </xsd:complexType>

conversion-value

The conversion-value complex type will be added and is used within an object-type-converter. It is used to specify data and Java object conversion values(s).

  <xsd:complexType name="conversion-value">
    <xsd:annotation>
      <xsd:documentation>

        @Target({})
        @Retention(RUNTIME)
        public @interface ConversionValue {
          /**
           * (Required) Specify the database value.
           */
          String dataValue();

          /**
           * (Required) Specify the object value.
           */
          String objectValue();
        }
      </xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="data-value" type="xsd:string"/>
    <xsd:attribute name="object-value" type="xsd:string"/>
  </xsd:complexType>

Example

  <object-type-converter name="sexConverter" data-type="java.lang.String" object-type="java.lang.String">
    <conversion-value data-value="F" object-value="Female"/>
    <conversion-value data-value="M" object-value="Male"/>
  </object-type-converter>

Design and processing

  • Build new org.eclipse.persistence.internal.jpa.metadata.converters.xml.XMLObjectTypeConverter that extends org.eclipse.persistence.internal.jpa.metadata.converters.MetadataObjectTypeConverter. Its only responsibility will be to override the metadata that is processed.
  • Processing is currently defined in the org.eclipse.persistence.internal.jpa.metadata.converters.MetadataObjectTypeConverter.
  • JBS: processing should allow multiple data-value for the same object-value, the first one should be processed normally, but additional data-values should be added as one-way conversions.

struct-converter

The struct-converter complex type will be added and is used to specify a spatial converter. Currently, internally only the JGeometry spatial type is supported (unless the user builds their own) and it maps to a org.eclipse.persistence.platform.database.oracle.converters.JGeometryConverter which converts the JGeometry values as they are read and written from the database.

  <xsd:complexType name="struct-converter">
    <xsd:annotation>
      <xsd:documentation>

        @Target({TYPE, METHOD, FIELD})
        @Retention(RUNTIME)
        public @interface StructConverter {
          /**
           * (Required) Name this converter. The name should be unique across the 
           * whole persistence unit.
           */
          String name();

          /**
           * (Required) The converter class to be used. This class must implement the
           * EclipseLink org.eclipse.persistence.mappings.converters.Converter interface.
           */
          String converter(); 
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="name" type="xsd:string" use="required">
    <xsd:attribute name="converter" type="xsd:string" use="required"/>
  </xsd:complexType>

Example

  <struct-converter name="JGeometry" converter="JGEOMETRY"/>

Design and processing

  • Build new org.eclipse.persistence.internal.jpa.metadata.converters.xml.XMLStructConverter that extends org.eclipse.persistence.internal.jpa.metadata.converters.MetadataStructConverter. Its only responsibility will be to override the metadata that is processed.
  • Processing is currently defined in the org.eclipse.persistence.internal.jpa.metadata.converters.MetadataStructConverter.

Mapping Annotations

  • The following new mapping related elements will be added.
  1. basic-collection
  2. basic-map
  3. collection-table

collection-table

A collection-table is used in conjunction with a basic-collection or a basic-map element. If no collection-table is defined with a basic-collection or basic-map then one will be defaulted. (see comment on name() below)

The following collection-table complex type will be added. See the basic-collection and basic-map elements for more information.

  <xsd:complexType name="collection-table">
    <xsd:annotation>
      <xsd:documentation>

        @Target({METHOD, FIELD})
        @Retention(RUNTIME)
        public @interface CollectionTable {
          /**
           * (Optional) The name of the collection table. If it is not specified, it is defaulted to the
           * concatenation of the following: the name of the source entity; "_" ; the name of the 
           * relationship property or field of the source entity.
           */
          String name() default ""; 

          /**
           * (Optional) The catalog of the table. It defaults to the persistence unit default catalog.
           */
          String catalog() default ""; 

          /**
           * (Optional) The schema of the table. It defaults to the persistence unit default schema.
           */
          String schema() default ""; 

          /**
           * (Optional) Used to specify a primary key column that is used as a foreign key to join to
           * another table. If the source entity uses a composite primary key, a primary key join column 
           * must be specified for each field of the composite primary key. In a single primary key case, 
           * a primary key join column may optionally be specified. Defaulting will apply otherwise as 
           * follows:
           * name, the same name as the primary key column of the primary table of the source entity.
           * referencedColumnName, the same name of primary key column of the primary table of the source 
           * entity.
           */
          PrimaryKeyJoinColumn[] primaryKeyJoinColumns() default {}; 
 
          /**
           * (Optional) Unique constraints that are to be placed on the table. These are only
           * used if table generation is in effect.
           */
          UniqueConstraint[] uniqueConstraints() default {}; 
       }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
      <xsd:element name="primary-key-join-column" type="orm:primary-key-join-column" minOccurs="0" maxOccurs="unbounded"/>
      <xsd:element name="unique-constraint" type="orm:unique-constraint" minOccurs="0" maxOccurs="unbounded"/>
    </xsd:sequence>
    <xsd:attribute name="name" type="xsd:string"/>
    <xsd:attribute name="catalog" type="xsd:string"/>
    <xsd:attribute name="schema" type="xsd:string"/>
  </xsd:complexType>

Example

See basic-map example or basic-collection example.

Design and processing

  • Processing of the collection-table will be performed when processing a basic-collection or basic-map. Therefore, the new accessor classes added to support those mappings will need to override the necessary method(s) to ensure an org.eclipse.persistence.internal.metadata.accessors.table.xml.XMLCollectionTable that subclasses the org.eclipse.persistence.internal.metadata.accessors.table.MetadataCollectionTable class is used in the processing.
  • The XMLCollectionTable's only responsibility will be to override the metadata that is processed.
  • For more processing details see org.eclipse.persistence.internal.jpa.metadata.accessors.BasicCollectionAccessor and org.eclipse.persistence.internal.jpa.metadata.accessors.BasicMapAccessor

basic-collection

The basic-collection element is used to map an org.eclipse.persistence.mappings.DirectCollectionMapping which stores a collection of simple types (String, Number, Date, etc.) into a single table. The table must store the value and a foreign key to the source object. A basic-collection is used in conjunction with a collection-table and/or convert if necessary. Note, a basic-collection may also be marked as private-owned.

  <xsd:complexType name="basic-collection">
    <xsd:annotation>
      <xsd:documentation>
        @Target({METHOD, FIELD})
        @Retention(RUNTIME)
        public @interface BasicCollection {
          /**
           * (Optional) Defines whether the value of the field or property should
           * be lazily loaded or must be eagerly fetched. The EAGER strategy is a 
           * requirement on the persistence provider runtime that the value must be 
           * eagerly fetched. The LAZY strategy is a hint to the persistence provider 
           * runtime. If not specified, defaults to LAZY.
           */
          FetchType fetch() default LAZY; 
 
          /**
           * (Optional) The name of the value column that holds the direct collection 
           * data. Defaults to the property or field name.
           */
          Column valueColumn() default @Column;
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
      <xsd:element name="value-column" type="orm:column" minOccurs="0"/>
      <xsd:element name="collection-table" type="orm:collection-table" minOccurs="0"/>
    </xsd:sequence>
    <xsd:attribute name="fetch" type="orm:fetch-type"/>
    <xsd:attribute name="convert" type="xsd:string"/>
    <xsd:attribute name="private-owned" type="xsd:boolean"/>
    <xsd:attribute name="join-fetch" type="orm:join-fetch-type">
  </xsd:complexType>

Example

  <basic-collection fetch="LAZY" private-owned="true" join-fetch="INNER">
    <value-column name="DESCRIPTION"/>
    <collection-table name="RESPONSIBILITIES">
      <primary-key-join-column name="EMPLOYEE_ID" referenced-column-name="EMP_ID">
    </collection-table>
  </basic-collection>

Design and processing

  • Build new org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLBasicCollectionAccessor that extends org.eclipse.persistence.internal.jpa.metadata.accessors.BasicCollectionAccessor. Its sole purpose will be to override the metatada that is processed.
  • For internal processing details see org.eclipse.persistence.internal.jpa.metadata.accessors.BasicCollectionAccessor.
  • If a basic-collection is specified on an attribute of type Map, an exception will be thrown. This will need to be handled in XMLClassAccessor (when building an XMLBasicCollectionAccessor)
  • org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLClassAccessor will be responsible for building XMLBasicCollectionAccessor's

basic-map

The basic-map xml element is used to map a oracle.toplink.mappings.BasicMapMapping which stores a collection of key-value pairs. The key and value must be simple types (String, Number, Date, etc.) and stored in a single table along with a foreing key to the source object. A basic-map can be used in conjunction with a collection-table. Note, a basic-map may also be marked as private-owned.

  <xsd:complexType name="basic-map">
    <xsd:annotation>
      <xsd:documentation>
        @Target({METHOD, FIELD})
        @Retention(RUNTIME)
        public @interface BasicMap {
          /**
           * (Optional) Defines whether the value of the field or property should
           * be lazily loaded or must be eagerly fetched. The EAGER strategy is a 
           * requirement on the persistence provider runtime that the value must be 
           * eagerly fetched. The LAZY strategy is a hint to the persistence provider 
           * runtime. If not specified, defaults to LAZY.
           */
          FetchType fetch() default LAZY;

          /**
           * (Optional) The name of the data column that holds the direct map key.
           * If the name on te key column is "", the name will default to:
           * the name of the property or field; "_key".
           */
          Column keyColumn();

          /**
           * (Optional) Specify the key converter. Default is equivalent to specifying
           * @Convert("none"), meaning no converter will be added to the direct map key.
           */
          Convert keyConverter() default @Convert;

          /**
           * (Optional) The name of the data column that holds the direct collection data.
           * Defaults to the property or field name.
           */
          Column valueColumn() default @Column;

          /**
           * (Optional) Specify the value converter. Default is equivalent to specifying 
           * @Convert("none"), meaning no converter will be added to the value column mapping.
           */
          Convert valueConverter() default @Convert;
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
      <xsd:element name="key-column" type="orm:column" minOccurs="0"/>    
      <xsd:element name="value-column" type="orm:column" minOccurs="0"/>    
      <xsd:element name="collection-table" type="xsd:collection-table" minOccurs="0"/>
    </xsd:sequence>
    <xsd:attribute name="fetch" type="orm:fetch-type"/>
    <xsd:attribute name="key-converter" type="xsd:string"/>
    <xsd:attribute name="value-converter" type="xsd:string"/>
    <xsd:attribute name="join-fetch" type="orm:join-fetch-type">
  </xsd:complexType>

Example

  <basic-map fetch="LAZY" private-owned="false" key-converter="licenseConverter" value-converter="Integer2String" join-fetch="OUTER">
    <key-column name="LICENSE"/>
    <value-column name="STATUS"/>
    <collection-table name="LICENSES">
      <primary-key-join-column name="RESTAURANT_ID" referenced-column-name="ID">
    </collection-table>
  </basic-map>

Design and processing

  • Build new org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLBasicMapAccessor that extends org.eclipse.persistence.internal.jpa.metadata.accessors.BasicMapAccessor. Its sole purpose will be to override the metatada that is processed.
  • For internal processing details see org.eclipse.persistence.internal.jpa.metadata.accessors.BasicMapAccessor's process method.
  • If a basic-map is specified on an attribute of type Map, an exception will be thrown. This will need to be handled in XMLClassAccessor (when building an XMLBasicMapAccessor)
  • org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLClassAccessor will be responsible for building XMLBasicMapAccessor's

private-owned

The private-owned element,

  <xsd:attribute name="private-owned" type="xsd:boolean"/>

used to mark a mapping as privately owned on the given entity, will be supported on the following complex types:

  • one-to-one
  • one-to-many
  • basic-collection
  • basic-map.

Example

  <one-to-many name="phoneNumbers" target-entity="my.PhoneNumber" mapped-by="owner" private-owned="true">
    ....
  </one-to-many>

  <one-to-one name="manager" target-entity="my.Employee" private=owned="false">
    ....
  </one-to-many>

See basic-collection and basic-map for more examples.

Design and processing

  • The existing org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLOneToOneAccessor and org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLOneToManyAccessor will need to implement the necessary method to override the metadata processing of the private owned value. The basic-collection and basic-map implementations will also be responsible for implementing this override.
  • JBS: ensure that a one-to-many with a join table is processed, it should not be ignored.

Optimistic Locking

The 5 supported locking policies were previously supported through the usage of an @OptimisticLocking annotation. The supported EclipseLink policies are:

  • org.eclipse.persistence.descriptors.AllFieldsLockingPolicy
  • org.eclipse.persistence.descriptors.ChangedFieldsLockingPolicy
  • org.eclipse.persistence.descriptors.SelectedFieldsLockingPolicy
  • org.eclipse.persistence.descriptors.VersionLockingPolicy
  • org.eclipse.persistence.descriptors.TimestampLockingPolicy

optimistic-locking

The optimistic-locking complex type will be added is used to specify the type of optimistic locking ExclipseLink should use when updating or deleting entities.

The optimistic-locking element,

  <xsd:element name="optimistic-locking" type="orm:optimistic-locking" minOccurs="0"/>

will be supported on the following complex types:

  • entity
  • mapped-superclass

JBS: missing defaults

  <xsd:complexType name="optimistic-locking">
    <xsd:annotation>
      <xsd:documentation>
       @Target({TYPE})
       @Retention(RUNTIME)
       public @interface OptimisticLocking {
         /**
          * (Optional) The type of optimistic locking policy to use.
          */
         OptimisticLockingType type() default VERSION_COLUMN;

         /**
          * (Optional) For an optimistic locking policy of type SELECTED_COLUMNS, this annotation
          * member becomes a (Required) field.
          */
         Column[] selectedColumns() default {};

         /**
          * (Optional) Specify where the optimistic locking policy should cascade lock. Currently
          * only supported with VERSION_COLUMN locking.
          */
         boolean cascade() default false;
       }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:sequence>
      <xsd:element name="selected-column" type="orm:column" minOccurs="0" maxOccours="unbounded"/>    
    </xsd:sequence>
    <xsd:attribute name="type" type="orm:optimisitic-locking-type"/>
    <xsd:attribute name="cascade" type="xsd:boolean"/>
  </xsd:complexType>

optimistic-locking-type

The optimistic-locking-type simple type will be added and is used in conjunction with the optimistic-locking complex type.

  <xsd:simpleType name="optimistic-locking-type">
    <xsd:annotation>
      <xsd:documentation>
        public enum OptimisticLockingType {
          /**
           * Using this type of locking policy compares every field in the table
           * in the WHERE clause when doing an update or a delete. If any field
           * has been changed, an optimistic locking exception will be thrown.
           */
          ALL_COLUMNS,

          /**
           * Using this type of locking policy compares only the changed fields
           * in the WHERE clause when doing an update. If any field has been
           * changed, an optimistic locking exception will be thrown. A delete
           * will only compare the primary key.
           */
          CHANGED_COLUMNS,

          /**
           * Using this type of locking compares selected fields in the WHERE
           * clause when doing an update or a delete. If any field has been
           * changed, an optimistic locking exception will be thrown. Note that
           * the fields specified must be mapped and not be primary keys.
           */
          SELECTED_COLUMNS,

          /**
           * Using this type of locking policy compares a single version number
           * in the where clause when doing an update. The version field must be
           * mapped and not be the primary key.
           */
          VERSION_COLUMN
        }
      </xsd:annotation>
    </xsd:documentation>
    <xsd:restriction base="xsd:token">
      <xsd:enumeration value="ALL_COLUMNS"/>
      <xsd:enumeration value="CHANGED_COLUMNS"/>
      <xsd:enumeration value="SELECTED_COLUMNS"/>
      <xsd:enumeration value="VERSION_COLUMN"/>
    </xsd:restriction>
  </xsd:simpleType>

Setting an optimistic-locking on an entity 'could' override any version specification found on an attribute for the given entity. No exception is thrown, instead a warning message will be logged. Since version was introduced by JPA, a version element without an optimistic-locking element is still a valid way to define a VersionLockingPolicy on the source entity.

Example

  <entity name="Employee" class="my.Employee" access="PROPERTY" change-tracking="DEFERRED">
  
    ....

    <optimistic-locking type="SELECTED_COLUMNS" cascade="false">
      <selected-column name="id"/>
      <selected-column name="firstName"/>
    </optimistic-locking>

    ....

  </entity>

Design and processing

  • Build new org.eclipse.persistence.internal.jpa.metadata.optimisticlocking.xml.XMLOptimisticLocking that extends org.eclipse.persistence.internal.jpa.metadata.optimisticlocking.MetadataOptimisticLocking. Its sole purpose will be to override the metatada values processed for the optimistic locking policy.
  • org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLClassAccessor will be responsible for building the XMLOptimisticLocking.

Entity Caching

EclipseLink uses identity maps to cache objects for performance and maintain object identity. Users can control the cache and its behavior by specifying the cache element on their entity classes.

cache

The cache complex type will be created and is used to specify the caching strategy for a given entity. In the case of inheritance, a cache element can only be defined on the root of the inheritance hierarchy. The cache complex type will make use of two new simple types as well, cache-type and cache-coordination-type.

The cache element,

  <xsd:element name="cache" type="orm:cache" minOccurs="0"/>

will be supported on the following complex types:

  • entity
  • mapped-superclass

JBS: missing defaults, missing size.

  <xsd:complexType name="cache">
    <xsd:annotation>
      <xsd:documentation>
        @Target({TYPE})
        @Retention(RUNTIME)
        public @interface Cache {
          /**
           * (Optional) The type of cache to use.
           */ 
          CacheType type() default SOFT_WEAK;

          /**
           * (Optional) Cached instances in the shared cache or a client isolated cache.
           */ 
          boolean isolated() default false;

          /**
           * (Optional) Expire cached instance after a fix period of time (ms). 
           * Queries executed against the cache after this will be forced back 
           * to the database for a refreshed copy
           */ 
          int expiry() default -1; // minus one is no expiry.

          /**
           * (Optional) Expire cached instance a specific time of day. Queries 
           * executed against the cache after this will be forced back to the 
           * database for a refreshed copy
           */ 
          TimeOfDay expiryTimeOfDay() default @TimeOfDay(specified=false);

          /**
           * (Optional) Force all queries that go to the database to always 
           * refresh the cache.
           */ 
          boolean alwaysRefresh() default false;

          /**
           * (Optional) For all queries that go to the database, refresh the cache 
           * only if the data received from the database by a query is newer than 
           * the data in the cache (as determined by the optimistic locking field)
           */ 
          boolean refreshOnlyIfNewer() default false;

          /**
           * (Optional) Setting to true will force all queries to bypass the 
           * cache for hits but still resolve against the cache for identity. 
           * This forces all queries to hit the database.
           */ 
          boolean disableHits() default false;

          /**
           * (Optional) The cache coordination mode.
           */ 
          CacheCoordinationType coordinationType() default SEND_OBJECT_CHANGES;
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:choice>
      <xsd:element name="expiry" type="xsd:integer" minOccurs=0/>
      <xsd:element name="expiry-time-of-day" type="orm:time-of-day" minOccurs=0/>
    </xsd:choice>
    <xsd:attribute name="isolated" type="xsd:boolean/>
    <xsd:attribute name="type" type="orm:cache-type"/>
    <xsd:attribute name="always-refresh" type="xsd:boolean"/>
    <xsd:attribute name="refresh-only-if-newer" type="xsd:boolean"/>
    <xsd:attribute name="disable-hits" type="xsd:boolean"/>
    <xsd:attribute name="coordination-type" type="orm:cache-coordination-type"/>
  </xsd:complexType>

cache-type

The cache-type simple type is used within the cache complex type.

JBS: missing SOFT type.

  <xsd:simpleType name="cache-type">
    <xsd:annotation>
      <xsd:documentation>

        public enum CacheType {
          /**
           * Provides full caching and guaranteed identity. Caches all objects
           * and does not remove them. 
           * WARNING: This method may be memory intensive when many objects are 
           * read.
           */
          FULL,

          /**
           * Similar to the FULL identity map except that the map holds the
           * objects using weak references. This method allows full garbage
           * collection and provides full caching and guaranteed identity.
           */
          WEAK,

          /**
           * Similar to the WEAK identity map except that it maintains a
           * most-frequently-used sub-cache. The size of the sub-cache is
           * proportional to the size of the identity map as specified by
           * descriptor's setIdentityMapSize() method. The sub-cache
           * uses soft references to ensure that these objects are
           * garbage-collected only if the system is low on memory.
           */
          SOFT_WEAK,

          /**
           * Identical to the soft cache weak (SOFT_WEAK) identity map except 
           * that it uses hard references in the sub-cache. Use this identity 
           * map if soft references do not behave properly on your platform.
           */
          HARD_WEAK,

          /**
           * A cache identity map maintains a fixed number of objects
           * specified by the application. Objects are removed from the cache
           * on a least-recently-used basis. This method allows object
           * identity for the most commonly used objects.
           * WARNING: Furnishes caching and identity, but does not guarantee 
           * identity.
           */
          CACHE,

          /**
           * WARNING: Does not preserve object identity and does not cache 
           * objects.
           */
          NONE
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base="xsd:token">
      <xsd:enumeration value="FULL"/>
      <xsd:enumeration value="WEAK"/>
      <xsd:enumeration value="SOFT_WEAK"/>
      <xsd:enumeration value="HARD_WEAK"/>
      <xsd:enumeration value="CACHE"/>
      <xsd:enumeration value="NONE"/>
    </xsd:restriction>
  </xsd:simpleType>

cache-coordination-type

The cache-coordination-type simple type is used within the cache complex type.

  <xsd:simpleType name="cache-coordination-type">
    <xsd:annotation>
      <xsd:documentation>

          public enum CacheCoordinationType {
          /**
           * Sends a list of changed objects including data about the changes. This data is merged into 
           * the receiving cache.
           */
          SEND_OBJECT_CHANGES,

          /**
           * Sends a list of the identities of the objects that have changed. The receiving cache 
           * invalidates the objects (rather than changing any of the data)
           */
          INVALIDATE_CHANGED_OBJECTS,

          /**
           * Same as SEND_OBJECT_CHANGES except it also includes any newly created objects from the 
           * transaction.
           */
          SEND_NEW_OBJECTS_WITH_CHANGES,

          /**
           * Does no cache coordination.
           */
          NONE
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base="xsd:token">
      <xsd:enumeration value="SEND_OBJECT_CHANGES"/>
      <xsd:enumeration value="INVALIDATE_CHANGED_OBJECTS"/>
      <xsd:enumeration value="SEND_NEW_OBJECTS_WITH_CHANGES"/>
      <xsd:enumeration value="NONE"/>
    </xsd:restriction>
  </xsd:simpleType>

time-of-day

A time-of-day complex type is used to specify a specific time of day using a Calendar instance. It is used used within the cache complex type.

  <xsd:complexType name="time-of-day">
    <xsd:annotation>
      <xsd:documentation>
        
        @Target({})
        @Retention(RUNTIME)
        public @interface TimeOfDay {
          /**
           * (Optional) Hour of the day.
           */ 
          int hour() default 0;

          /**
           * (Optional) Minute of the day.
           */ 
          int minute() default 0;

          /**
           * (Optional) Second of the day.
           */ 
          int second() default 0;

          /**
           * (Optional) Millisecond of the day.
           */ 
          int millisecond() default 0;

          /**
           * Internal use. Do not modify.
           */ 
          boolean specified() default true;
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="hour" type="xsd:integer"/>
    <xsd:attribute name="minute" type="xsd:integer"/>
    <xsd:attribute name="second" type="xsd:integer"/>
    <xsd:attribute name="millisecond" type="xsd:integer"/>
  </xsd:complexType>

Example

  <cache type="FULL" isolated="false" always-refresh="true" refresh-only-if-newer="true" disable-hits="true" coordination-type="INVALIDATE_CHANGED_OBJECTS>

    ....

    <expiry>1000</expiry>
    or
    <expiry-time-of-day hour="0" minute="1" second="10" millisecond="3"/>

    ....

  </cache>

Design and processing

  • org.eclipse.peristence.internal.jpa.metadata.accessors.xml.XMLClassAccessor will need to override the necessary methods from org.eclipse.persistence.internal.jpa.metadata.accessors.ClassAccessor to ensure the xml metadata is processed.

Change Tracking

A new change-tracking-type simple type will be added and the change-tracking attribute,

JBS: Might be better as an element.

  <xsd:attribute name="change-tracking" type="orm:change-tracking-type"/>

will be supported on the following complex types:

  • entity
  • mapped-superclass
  • JBS: I think embeddable as well.

change-tracking

  <xsd:simpleType name="change-tracking-type">
    <xsd:annotation>
      <xsd:documentation>
        public enum ChangeTrackingType {
          /**
           * An ATTRIBUTE change tracking type allows change tracking at the attribute 
           * level of an object. Objects with changed attributes will be processed in 
           * the commit process to include any changes in the results of the commit.
           * Unchanged objects will be ignored.
           */
          ATTRIBUTE,

          /**
           * An OBJECT change tracking policy allows an object to calculate for itself 
           * whether it has changed. Changed objects will be processed in the commit 
           * process to include any changes in the results of the commit.
           * Unchanged objects will be ignored.
           */
          OBJECT,

          /**
           * A DEFERRED change tracking policy defers all change detection to the 
           * UnitOfWork's change detection process. Essentially, the calculateChanges() 
           * method will run for all objects in a UnitOfWork. 
           * This is the default ObjectChangePolicy
           */
          DEFERRED,

          /**
           * Will not set any change tracking policy.
           */
          AUTO
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base="xsd:token">
      <xsd:enumeration value="ATTRIBUTE"/>
      <xsd:enumeration value="OBJECT"/>
      <xsd:enumeration value="DEFERRED"/>
      <xsd:enumeration value="AUTO"/>
    </xsd:restriction>
  </xsd:simpleType>

Example

  <entity name="Employee" class="my.Employee" access="PROPERTY" change-tracking="DEFERRED">
   
    ....   

  </entity>

Design and processing

  • org.eclipse.peristence.internal.jpa.metadata.accessors.xml.XMLClassAccessor will need to override the necessary methods from org.eclipse.persistence.internal.jpa.metadata.accessors.ClassAccessor to ensure the xml metadata is processed.

Descriptor Customizer

customizer

The customizer attribute is used to specify a class that implements the org.eclipse.persistence.tools.sessionconfiguration.DescriptorCustomizer interface and that is to be run against a class' descriptor after all metadata processing has been completed. In the case of inheritance, a customizer is not inherited from its parent classes.

The customizer attribute,

JBS: Might be better as an element.

  <xsd:attribute name="customizer" type="xsd:string"/>

will be supported on the following complex types:

  • entity
  • mapped-superclass
  • embeddable

Example

  <entity name="Employee" class="my.Employee" access="PROPERTY" customizer="my.employee.Customizer">
    ....
  </entity>

  <mapped-superclass class="my.Beverage" access="FIELD" customizer="my.beverage.Customizer">
    ....
  </mapped-superclass>

  <embeddable class="my.EmploymentPeriod" access="PROPERTY" customizer="my.employmentPeriod.Customizer">
    ....
  </embeddable>

Design and processing

  • org.eclipse.persistence.internal.metadata.accessors.xml.XMLClassAccessor will need to override the necessary method(s) from org.eclipse.persistence.internal.metadata.accessors.ClassAccessor to ensure the xml metadata is processed.

read-only

The read-only element,

  <xsd:attribute name="read-only" type="xsd:boolean"/>

is used to specify that a class is read only. In the case of inheritance, a read-only value can only be defined on the root of the inheritance hierarchy. The read-only attribute will be supported on the following complex types:

  • entity
  • mapped-superclass

Example

  <entity name="Employee" class="my.Employee" access="PROPERTY" read-only="true">
    ....
  </entity>

  <mapped-superclass class="my.Beverage" access="FIELD" read-only="false">
    ....
  </mapped-superclass>

Design and processing

  • org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLClassAccessor will need to override the necessary methods from org.eclipse.persistence.internal.jpa.metadata.accessors.ClassAccessor to ensure the xml metadata is processed.

Returning policy

Allows for INSERT or UPDATE operations to return values back into the object being written. This allows for table default values, trigger or stored procedures computed values to be set back into the object.

return-insert

The return-insert complex type will be added and the return-insert element,

  <xsd:element name="return-insert" type="orm:return-insert" minOccurs="0"/>

will be supported on the following complex types:

  • basic
  • JBS: also id, version
  <xsd:complexType name="return-insert">
    <xsd:annotation>
      <xsd:documentation>

        @Target({METHOD, FIELD})
        @Retention(RUNTIME)
        public @interface ReturnInsert {
          boolean returnOnly() default false;
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="return-only" type="xsd:boolean"/>
  </xsd:complexType>

Example

  <basic name="areaCode">
    <column name="AREA_CODE"/>
    <return-insert read-only="true"/>
  </basic>

Design and processing

  • org.eclipse.persistence.internal.jpa.metadata.accessors.XMLBasicAccessor will have to override the appropriate method(s) to ensure the xml metadata is used in the processing.

return-update

The return-update complex type will be added and the return-update element,

  <xsd:element name="return-update" type="orm:return-update" minOccurs="0"/>

will be supported on the following complex types:

  • basic
  • JBS: also version?
  <xsd:complexType name="return-update">
    <xsd:annotation>
      <xsd:documentation>

        @Target({METHOD, FIELD})
        @Retention(RUNTIME)
        public @interface ReturnUpdate {}

      </xsd:documentation>
    </xsd:annotation>
  </xsd:complexType>

Example

  <basic name="firstName">
    <column name="F_NAME"/>
    <return-update/>
  </basic>

Design and processing

  • org.eclipse.persistence.internal.jpa.metadata.accessors.XMLBasicAccessor will have to override the appropriate method(s) to ensure the xml metadata is used in processing.

Stored procedure query

named-stored-procedure-query

A named-stored-procedure-query complex type will be added and will allow the definition of queries that call stored procedures as named queries. These queries will be available from the entity, mapped-superclass and embedabble complex types.

JBS: missing default for returns-result-set, typo shouod=>should

  <xsd:complexType name="named-store-procedure-query">
    <xsd:annotation>
      <xsd:documentation>

        @Target({TYPE})
        @Retention(RUNTIME)
        public @interface NamedStoredProcedureQuery {
          /**
           * (Required) Unique name that references this stored procedure query.
           */
          String name();

          /**
           * (Optional) Query hints.
           */
          QueryHint[] hints() default {};

          /**
           * (Optional) Refers to the class of the result.
           */
          Class resultClass() default void.class;

          /**
           * (Optional) The name of the SQLResultMapping.
           */
          String resultSetMapping() default "";

          /**
           * (Required) The name of the stored procedure.
           */
          String procedureName();

          /**
           * (Optional) Whether the query shouod return a result set.
           */
          boolean returnsResultSet() default true; 

          /**
           * (Optional) Defines arguments to the stored procedure.
           */
          StoredProcedureParameter[] procedureParameters() default {};
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:complexContent>
      <xsd:sequence>
        <xsd:element name="hint" type="orm:hint" minOccurs="0" maxOccurs="unbounded">
        <xsd:element name="procedure-parameter" type="orm:procedure-parameter" minOccurs="0" maxOccurs="unbounded">
      </xsd:sequence>
    <xsd:attribute name="name" type="xsd:string" use="required"/>
    <xsd:attribute name="result-class" type="xsd:string"/>
    <xsd:attribute name="result-set-mapping" type="xsd:string"/>
    <xsd:attribute name="procedure-name" type="xsd:string" user="required"/>
    <xsd:attribute name="returns-result-set" type="xsd:boolean"/>
  </xsd:complexType>

stored-procedure-parameter

JBS: missing complex (PLSQL) type support.

  <xsd:complexType name="stored-procedure-parameter">
    <xsd:annotation>
      <xsd:documentation>

        @Target({})
        @Retention(RUNTIME)
        public @interface StoredProcedureParameter {
          /**
           * (Optional) The direction of the stored procedure parameter.
           */
          Direction procedureParameterDirection() default IN;

          /**
           * (Optional) Stored procedure parameter name.
           */
          String name() default "";

          /**
           * (Required) The query parameter name.
           */
          String queryParameter();

          /**
           * (Optional) The type of Java class desired back from the procedure, 
           * this is dependent on the type returned from the procedure.
           */
          Class type() default void.class;

          /**
           * (Optional) The JDBC type code, this dependent on the type returned 
           * from the procedure.
           */
          int jdbcType() default -1;

          /**
           * (Optional) The JDBC type name, this may be required for ARRAY or 
           * STRUCT types.
           */
          String jdbcTypeName() default "";
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:attribute name="procedure-parameter-direction" type="orm:direction">
    <xsd:attribute name="name" type="xsd:string"/>
    <xsd:attribute name="query-parameter" type="xsd:string" use="required"/>
    <xsd:attribute name="type" type="xsd:string"/>
    <xsd:attribute name="jdbc-type" type="xsd:integer"/>
    <xsd:attribute name="jdbc-type-name" type="xsd:string"/>
  </xsd:complexType>

direction-type

  <xsd:simpleType name="direction-type">
    <xsd:annotation>
      <xsd:documentation>
        public enum Direction {
          /**
           * Input parameter
           */
          IN,

          /**
           * Output parameter
           */
          OUT,

          /**
           * Input and output parameter
           */
          IN_OUT,

          /**
           * Output cursor
           */
          OUT_CURSOR
        }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base="xsd:token">
      <xsd:enumeration value="IN"/>
      <xsd:enumeration value="OUT"/>
      <xsd:enumeration value="IN_OUT"/>
      <xsd:enumeration value="OUT_CURSOR"/>
    </xsd:restriction>
  </xsd:simpleType>

Example

  <named-stored-procedure-query name="ReadEmployee" procedureName="Read_Employee">
    <stored-procedure-parameter queryParameter="EMP_ID"/>
  </named-stored-procedure-query>

Design and processing

  • Build new org.eclipse.persistence.internal.jpa.metadata.queries.xml.XMLNamedStoredProcedureQuery that extends org.eclipse.persistence.internal.jpa.metadata.queries.MetadataNamedStoredProcesureQuery. Its sole purpose will be to override the metatada that is processed.
  • Build new org.eclipse.persistence.internal.jpa.metadata.queries.xml.XMLStoredProcedureParameter that extends org.eclipse.persistence.internal.jpa.metadata.queries.MetadataStoredProcesureParameter. Its sole purpose will be to override the metatada that is processed.
  • org.eclipse.persistence.internal.jpa.metadata.accessors.XMLClassAccessor will be responsible for building XMLNamedStoredProcedureQuery's.

Join Fetch

A join fetch setting allows related objects to be joined and read in the same query as the source object. A join-fetch attribute,

JBS: missing default, INNER

  <xsd:attribute name="join-fetch" type="orm:join-fetch-type">

will be supported on the following complex types.

  • one-to-one
  • many-to-one
  • one-to-many
  • many-to-many
  • basic-collection
  • basic-map.

join-fetch-type

  <xsd:simpleType name="join-fetch-type">
    <xsd:annotation>
      <xsd:documentation>
        public enum JoinFetchType {
        /**
         * An inner join is used to fetch the related object.
         * This does not allow for null/empty values.
         */
        INNER,

        /**
         * An inner join is used to fetch the related object.
         * This allows for null/empty values.
         */
        OUTER,
      }

      </xsd:documentation>
    </xsd:annotation>
    <xsd:restriction base="xsd:token">
      <xsd:enumeration value="INNER"/>
      <xsd:enumeration value="OUTER"/>
    </xsd:restriction>
  </xsd:simpleType>

Example

  • See basic-collection or basic-map for an example.

Design and processing

  • Processing of the join-fetch type will be done per individual supported mapping accessor classes. For example, org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLOneToOneAccessor will be responsible for overriding the necessary method from org.eclipse.persistence.internal.jpa.metadata.accessors.OneToOneAccessor to ensure the xml value is used in the processing. The same holds true for all the other xml mapping accessors and their parent classes.

Mutable

A mutable setting can be used on a basic mapping. It can be used on complex field types to indicate that the value itself can be changed or not changed (instead of being replaced). Mutable basic mappings affect the overhead of change tracking, attribute change tracking can only be weaved with non-mutable mappings.

The mutable element,

  <xsd:attribute name="mutable" type="xsd:boolean">

will be supported on the following complex types:

  • basic

Example

  <basic name="bestBeforeDate" mutable="false">
    <column name="BB_DATE"/>
    <temporal>DATE</temporal>
  </basic>

Design and processing

  • org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLBasicAccessor will need to override the necessary method from org.eclipse.persistence.internal.jpa.metadata.accessors.BasicAccessor to esure the xml metadata is processed.

Questions and comments

  • JBS: attributes-complete - have a flag to indicate not to auto generate any unspecified attributes, this is important in XML when the class may continue to evolve.
  • JBS: allow sequence on non-id attribute
  • JBS: primary-key element to allow giving columns, (allow one-to-one pks, or including other fields such as the inheritance indicator, field from embeddable, etc.)
  • JBS: allow relationships and inheritance in embeddable
  • JBS: xsd allows a join-table on a one-to-one? eclipselink does not support this?
  • JBS: xsd allows a join-column on a one-to-many? I thought the spec did not allow this, make sure we support this correctly on annotations too.
  • JBS: should allow target-join-column in a one-to-one (allows complex target foreign keys and one-to-one without mappedBy)
  • JBS: missing eclipselink features, transformation, aggregate-collection, variable 1-1, xml-type, or-data-type, eis, serialized converter, class-instance converter, query-keys, mapping selection-criteria, custom-sql/calls, mapping custom-sql/calls, query sequence, unary-table sequence, copy-policy, instantiation-policy, fetch-groups, class-extractor, additional-join, multiple-table-join, multiple-table foreign-keys, inheritance-joins, additional events, does-exist, default timeout, interfaces, history, etc.