Skip to main content

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

Jump to: navigation, search

Difference between revisions of "Http://wiki.eclipse.org/EclipseLink/DesignDocs/JPA XML metadata extensions"

(converter)
(type-converter)
Line 102: Line 102:
 
       @Target({TYPE, METHOD, FIELD})
 
       @Target({TYPE, METHOD, FIELD})
 
       @Retention(RUNTIME)
 
       @Retention(RUNTIME)
       public @interface Converter {
+
       public @interface TypeConverter {
 
         /**
 
         /**
 
         * (Required) Name this converter. The name should be unique
 
         * (Required) Name this converter. The name should be unique

Revision as of 08:32, 20 September 2007

WARNING ... WORK IN PROGRESS ...

Design Specification: JPA XML metadata extensions

Document History

Date Author Version Description
2007-09-17 Guy Pelletier Initial Draft

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.xml file. This file will be a copy of the latest JPA orm.xml file plus the newly created xml element.

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.

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 coverter complex types will be added (converter, type-converter, object-type-converter) and there usage is specified through the convert attribute on those mapping elements that support using a converter. The converters can be specified at the following levels:

  • entity-mappings
  • entity
  • mapped-superclass
<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"/>

The new convert attribute will be added to the supported mapping types:

  • basic (existing)
  • basic-map (new, see basic-map section below)
  • basic-collection (new see basic-collection section below)

Warnings

  • Converter names are global across the persistence unit, therefore, must be unique. The first converter processed will be used, whereas, consecutive converters with the same name will be ignored and a warning message logged.

Exceptions

  • The name "none" and "serialized" are reserved for converter names. Any converter that attempts to use either of those values as their name will cause an exception to be thrown.

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

  • The org.eclipse.persistence.internal.jpa.metadata.converters.xml.XMLConverter class will be built and will extend the 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

  • The org.eclipse.persistence.internal.jpa.metadata.converters.xml.XMLTypeConverter class will be built and will extend the 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.MetadataConverter. (see previous design doc)

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="0" maxOccurs=unbounded/>
        <xsd:element name="default-object-value" type="xsd:string" minOccurs="0"/>
      </xsd:sequence>
    </xsd:entension>
  </xsd:complexContent>
</xsd:complexType>

<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

  • The org.eclipse.persistence.internal.jpa.metadata.converters.xml.XMLObjectConverter class should be built and extend the MetadataObjectConverter. 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.MetadataObjectConverter. (see previous design doc)
  • If multiple objectValue's are specified for the same dataValue an exception will be thrown.

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.

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

Design and processing

  • Processing of the collection-table is done within those mappings that support one. That is, basic-collection and basic-map. Therefore, the new accessor classes added to support those methogs will need to override the getCollectionTable() method to return an org.eclipse.persistence.internal.metadata.accessors.table.xml.XMLCollectionTable which will subclass the org.eclipse.persistence.internal.metadata.accessors.table.MetadataCollectionTable class.
  • The XMLCollectionTable's only responsibility will be to override the metadata that is processed.
  • If the source entity uses a composite primary key and the primary key join columns are not fully specified, then an exception will be thrown.

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. It is used in conjunction with the a collection-table and/or convert if necessary.

<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="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:complexType>


Design and processing

  • See design for @BasicCollection and @BasicMap for more information.
  • Build new org.eclipse.persistence.internal.jpa.metadata.accessors.tables.xml.XMLBasicCollectionAccessor that extends org.eclipse.persistence.internal.jpa.metadata.accessors.tables.BasicCollectionAccessor. It's sole purpose will be to override the metatadat that is processed.
  • If a basic-collection is specified on an attribute of type Map, an exception will be thrown.

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.

<xsd:complexType name="basic-collection">
  <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:attribute name="fetch" type="orm:fetch-type"/>
  <xsd:element name="key-column" type="orm:column" minOccurs="0"/>
  <xsd:attribute name="key-converter" type="xsd:convert" use="optional"/>
  <xsd:element name="value-column" type="orm:column" minOccurs="0"/>
  <xsd:attribute name="value-converter" type="xsd:convert" use="optional"/>
  <xsd:attribute name="collection-table" type="xsd:collection-table" use="optional"/>
</xsd:complexType>

Exceptions

  • If a basic-map is specified on an attribute of type Collection, an exception will be thrown.


Design and processing

  • See design for @BasicCollection and @BasicMap for more information.
  • Build new org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLBasicMapAccessor that extends org.eclipse.persistence.internal.jpa.metadata.accessors.BasicMapAccessor.
  • The XMLBasicCollectionAccessor's only responsibility will be to override the metadata that is processed.
  • XMLClassAccessor will be responsible for building XMLBasicMapAccessor's.
  • The matching up of converters with the key and value will throw an exception if the converter with

the matching name is not found. The converters are expected to be defined on the corresponding accessor.

private-owned

A private-owned element (used to mark a mapping as privately owned on the given entity) will now be supported within the following complex types: one-to-one, one-to-many as well as the new types, basic-collection and basic-map.

  • one-to-one
  <xsd:complexType name="one-to-one">
    
    ....

    <xsd:attribute name="private-owned" type="xsd:boolean"/>
  </xsd:complexType>
  • one-to-many
  <xsd:complexType name="one-to-many">
    
    ....

    <xsd:attribute name="private-owned" type="xsd:boolean"/>
  </xsd:complexType>
  • basic-collection (see basic-collection within this document)
  • basic-map (see basic-map withing this document)

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.

Optimistic Locking

The following annotation will be added to allow 5 different optimisitic locking policies implemented by TopLink. Namely:

  • oracle.toplink.descriptors.AllFieldsLockingPolicy
  • oracle.toplink.descriptors.ChangedFieldsLockingPolicy
  • oracle.toplink.descriptors.SelectedFieldsLockingPolicy
  • oracle.toplink.descriptors.VersionLockingPolicy
  • oracle.toplink.descriptors.TimestampLockingPolicy)

optimistic-locking

The @OptimisticLocking is used to specify the type of optimistic locking TopLink should use when updating or deleting entities.

@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;
}

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
}

Setting an @OptimisticLocking 'could' override any @Version specification on the entity. No exception is thrown, instead a warning message will be logged. Since @Version was introduced by JPA, a @Version without any @OptimisticLocking specification is still a valid way to define a VersionLockingPolicy on the source entity.

Warnings

  • If a @Version annotation is found on an entity with an OptimisticLocking policy type other than

VERSION_COLUMN, a log warning will be issued that states the @Version annotation is being ignored.

  • If selectedColumns are defined with any other optimistic locking type other than SELECTED_COLUMNS,

a log warning will be issued stating that those @Column specifications are being ignored.

Exceptions

  • An exception will be thrown if the SELECTED_COLUMNS type is specified and the selectedColumns are

not (which also includes if the name on Column is not specified)

  • An exception will be thrown if the VERSION_COLUMN type is specified and no corresponding @Version

is found.

Design

  • @OptimisticLocking is processed in ClassAccessor's process() method.
  • @Version is processed in DirectAccessor's process() method.

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 create and will be accessible to entity and mapped-superclass elements. 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 simply types as well, cache-type and cache-coordination-type.

<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:attribute name="type" type="orm:cache-type" use="optional"/>
  <xsd:element name="isolated" type="xsd:boolean use="optional"/>
  <xsd:choice>
    <xsd:attribute name="expiry" type="xsd:integer" minOccurs=0/>
    <xsd:attribute name="expiry-time-of-day" type="orm:time-of-day" minOccurs=0/>
  </xsd:choice>
  <xsd:attribute name="always-refresh" type="xsd:boolean" use="optional"/>
  <xsd:attribute name="refresh-only-if-newer" type="xsd:boolean" use="optional"/>
  <xsd:attribute name="disable-hits" type="xsd:boolean" use="optional"/>
  <xsd:attribute name="coordination-type" type="orm:cache-coordination-type" use="optional"/>
</xsd:complexType>

cache-type

The cache-type simple type is used within the cache complex 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" use="optional"/>
  <xsd:attribute name="minute" type="xsd:integer" use="optional"/>
  <xsd:attribute name="second" type="xsd:integer" use="optional"/>
  <xsd:attribute name="millisecond" type="xsd:integer" use="optional"/>
</xsd:complexType>

==== Design and processing ====
* An cache setting an inheritance subclass will be ignored. A log warning will be issued.
* @Cache values are processed in ClassAccessor's process() method.

== Change Tracking ==

=== change-tracking ===
{code}
@Target({TYPE})
@Retention(RUNTIME)
public @interface ChangeTracking {
    /**
     * (Optional) The type of change tracking to use.
     */ 
    ChangeTrackingType value() default AUTO;
}

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
}
{code}

==== Design and processing ====
descriptor.setObjectChangePolicy(new AttributeChangeTrackingPolicy()); // ATTRIBUTE
descriptor.setObjectChangePolicy(new ObjectChangeTrackingPolicy()); // OBJECT
descriptor.setObjectChangePolicy(new DeferredChangeDetectionPolicy()); // DEFERRED
descriptor.setObjectChangePolicy(new AutoChangeDetectionPolicy()): // AUTO
// NOTE: AutoChangeDetectionPolicy does not currently exist. It will need to be created.
* @ChangeTracking value is processed in ClassAccessor's process() method.

== Descriptor Customizer ==
=== customizer ===
The @Customizer annotation is used to specify a class that implements the 
oracle.toplink.tools.sessionconfiguration.DescriptorCustomizer interface and that is to
be run against a class' descriptor after all metadata processing has been completed.

The @Customizer annotation may be defined on an @Entity, @MappedSuperclass or @Embeddable. 
In the case of inheritance, a @Customizer is not inherited from its parent classes.

@Target({TYPE})
@Retention(RUNTIME)
public @interface Customizer {
    /**
     * Defines the name of the descriptor customizer that should be
     * applied to this entity's descriptor.
     */
    Class value(); 
}

==== Design and processing ====
Class customizerClass = Customizer.value();
try {
    DescriptorCustomizer customizer = (DescriptorCustomizer) customizerClass.newInstance();
    customizer.customize(descriptor);
} catch (Exception ex) {
    // should be called through the appropriate validator
    ValidationException.errorInstantiatingDescriptorCustomizer(customizerClass , ex);
}

* @Customizer values should be processed after pre-deploy. That is, in deploy, after the entity 
listeners and queries have been processed, another call should be made to process the descriptor 
customizers. This must be the last call to the metadata processor to manipulate metadata.

=== read-only ===
The read-only element will be added the entity and mapped-superclass elements. It 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.

<code><pre>
<xsd:complexType name="entity">

  ....

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

<xsd:complexType name="mapped-superclass">

  ....

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

Design and Processing

  • The org.eclipse.persistence.internal.jpa.metadata.accessors.xml.XMLClassAccessor will need to implement the processReadOnly() method that will override processing the value from annotations since XMLClassAccessor extends the org.eclipse.persistence.internal.jpa.metadata.accessors.ClassAccessor.

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.

@ReturnInsert

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

   boolean returnOnly() default false;

} {code}

Warnings:

  • A @ReturnInsert annotation can only be specified for a @Basic mapping. If used with @BasicCollection,

@BasicMap, @EmbeddedId, @Embedded, @ManyToMany, @ManyToOne, @OneToMany or @OneToOne, a log warning will be issued.

  • Design and processing*

{code} // For both examples, a database field is created from the @Column (if specified), // otherwise defaulted as normal for any direct to field mapping. This also takes // into consideration @AttributeOverride from a subclass of a @MappedSuperclass.

// Example 1 descriptor.getReturningPolicy().addFieldForInsert(field);

// Example 2 descriptor.getReturningPolicy().addFieldForInsertReturnOnly(field); {code}

  • Design*
  • Processed in BasicAccessor's process() method.

@ReturnUpdate

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

Warnings:

  • A @ReturnUpdate annotation can only be specified for a @Basic mapping. If used with

@BasicCollection, @BasicMap, @EmbeddedId, @Embedded, @ManyToMany, @ManyToOne, @OneToMany or @OneToOne, a log warning will be issued.

Design and processing

{code} // A database field is created from the @Column (if specified), otherwise defaulted // as normal for any direct to field mapping. descriptor.getReturningPolicy().addFieldForUpdate(field); {code}

  • Processed in BasicAccessor's process() method.

Stored procedure query

@NamedStoredProcedureQuery

@NamedStoredProcedureQuery allows the definition of queries that call stored procedures as named queries.

{code} @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 {};

}

@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 "";

}

public enum Direction {

   /**
    * Input parameter
    */
   IN,
   /**
    * Output parameter
    */
   OUT,
   /**
    * Input and output parameter
    */
   IN_OUT,
   /**
    * Output cursor
    */
   OUT_CURSOR

} {code}

Design and processing

  • If more than one StoreProcedureQuery of type OUTPUT_CURSOR is specified, an exception will be thrown.

{code} // Process name(). // Check if a named stored procedure query with that name already exists, and if so, log a // warning message.

// If there is a resultClass() ReadAllQuery query = new ReadAllQuery(resultClass()); // ... process the stored procedure paramaters (see below) ...

// If there is a resultSetMapping() ResultSetMappingQuery query = new ResultSetMappingQuery(); query.setSQLResultSetMappingName(resultSetMapping()); // ... process the stored procedure paramaters (see below) ...

// If there is no resultClass() or resultSetMapping() ResultSetMappingQuery query = new ResultSetMappingQuery(); // ... process the stored procedure paramaters (see below) ...

// Build a StoredProcedureCall. StoredProcedureCall call = new StoredProcedureCall();

// Process procedureName() to set the procedure name on the call. call.setProcedureName(procedureName());

// Process returnsResultSet() call.setReturnsResultSet(returnsResultSet());

// Processing the stored procedure parameters ...

// Process procedureParameterDirection() ... String argumentFieldName = queryParameter(); String procedureParameterName = name().equals("") ? argumentFieldName : name();

// ** For IN direction ** // If type() is specified call.addNamedArgument(procedureParameterName, argumentFieldName, type()); // If jdbcType() is specified call.addNamedArgument(procedureParameterName, argumentFieldName, jdbcType()); // If jdbcType() and jdbcTypeName() are specified call.addNamedArgument(procedureParameterName, argumentFieldName, jdbcType(), jdbcTypeName()); // If no types are specified call.addNamedArgument(procedureParameterName, argumentFieldName); // Then add the argument to the query. query.addArgument(argumentFieldName);

// ** For OUT direction ** // If type() is specified call.addNamedOutputArgument(procedureParameterName, argumentFieldName, type()); // If jdbcType() is specified call.addNamedOutputArgument(procedureParameterName, argumentFieldName, jdbcType()); // If jdbcType() and jdbcTypeName() are specified call.addNamedOutputArgument(procedureParameterName, argumentFieldName, jdbcType(), jdbcTypeName()); // If no types are specified call.addNamedOutputArgument(procedureParameterName, argumentFieldName); // Then add the argument to the query. query.addArgument(argumentFieldName);

// ** For IN_OUT direction ** // If type() is specified call.addNamedInOutputArgument(procedureParameterName, argumentFieldName, argumentFieldName, type()); // If jdbcType() is specified call.addNamedInOutputArgument(procedureParameterName, argumentFieldName, argumentFieldName, jdbcType()); // If jdbcType() and jdbcTypeName() are specified call.addNamedInOutputArgument(procedureParameterName, argumentFieldName, argumentFieldName, jdbcType(), jdbcTypeName()); // If no types are specified call.addNamedInOutputArgument(procedureParameterName, argumentFieldName); // Then add the argument to the query. query.addArgument(argumentFieldName);

// ** For OUT_CURSOR direction ** call.useNamedCursorOutputAsResultSet(argumentFieldName);

// Process hints() // Same as @NamedQuery and @NamedNativeQuery

// And finally ... query.setCall(call); session.addQuery(query); {code}

  • Design*
  • Processed in ClassAccessor, during the same call from MetadataProcessor to process named query annotations.

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.

@ReturnInsert

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

   boolean returnOnly() default false;

} {code}

Warnings:

  • A @ReturnInsert annotation can only be specified for a @Basic mapping. If used with @BasicCollection,

@BasicMap, @EmbeddedId, @Embedded, @ManyToMany, @ManyToOne, @OneToMany or @OneToOne, a log warning will be issued.

  • Design and processing*

{code} // For both examples, a database field is created from the @Column (if specified), // otherwise defaulted as normal for any direct to field mapping. This also takes // into consideration @AttributeOverride from a subclass of a @MappedSuperclass.

// Example 1 descriptor.getReturningPolicy().addFieldForInsert(field);

// Example 2 descriptor.getReturningPolicy().addFieldForInsertReturnOnly(field); {code}

  • Design*
  • Processed in BasicAccessor's process() method.

@ReturnUpdate

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

Warnings:

  • A @ReturnUpdate annotation can only be specified for a @Basic mapping. If used with

@BasicCollection, @BasicMap, @EmbeddedId, @Embedded, @ManyToMany, @ManyToOne, @OneToMany or @OneToOne, a log warning will be issued.

Design and processing

{code} // A database field is created from the @Column (if specified), otherwise defaulted // as normal for any direct to field mapping. descriptor.getReturningPolicy().addFieldForUpdate(field); {code}

  • Processed in BasicAccessor's process() method.

Stored procedure query

@NamedStoredProcedureQuery

@NamedStoredProcedureQuery allows the definition of queries that call stored procedures as named queries.

{code} @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 {};

}

@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 "";

}

public enum Direction {

   /**
    * Input parameter
    */
   IN,
   /**
    * Output parameter
    */
   OUT,
   /**
    * Input and output parameter
    */
   IN_OUT,
   /**
    * Output cursor
    */
   OUT_CURSOR

} {code}

Design and processing

  • If more than one StoreProcedureQuery of type OUTPUT_CURSOR is specified, an exception will be thrown.

{code} // Process name(). // Check if a named stored procedure query with that name already exists, and if so, log a // warning message.

// If there is a resultClass() ReadAllQuery query = new ReadAllQuery(resultClass()); // ... process the stored procedure paramaters (see below) ...

// If there is a resultSetMapping() ResultSetMappingQuery query = new ResultSetMappingQuery(); query.setSQLResultSetMappingName(resultSetMapping()); // ... process the stored procedure paramaters (see below) ...

// If there is no resultClass() or resultSetMapping() ResultSetMappingQuery query = new ResultSetMappingQuery(); // ... process the stored procedure paramaters (see below) ...

// Build a StoredProcedureCall. StoredProcedureCall call = new StoredProcedureCall();

// Process procedureName() to set the procedure name on the call. call.setProcedureName(procedureName());

// Process returnsResultSet() call.setReturnsResultSet(returnsResultSet());

// Processing the stored procedure parameters ...

// Process procedureParameterDirection() ... String argumentFieldName = queryParameter(); String procedureParameterName = name().equals("") ? argumentFieldName : name();

// ** For IN direction ** // If type() is specified call.addNamedArgument(procedureParameterName, argumentFieldName, type()); // If jdbcType() is specified call.addNamedArgument(procedureParameterName, argumentFieldName, jdbcType()); // If jdbcType() and jdbcTypeName() are specified call.addNamedArgument(procedureParameterName, argumentFieldName, jdbcType(), jdbcTypeName()); // If no types are specified call.addNamedArgument(procedureParameterName, argumentFieldName); // Then add the argument to the query. query.addArgument(argumentFieldName);

// ** For OUT direction ** // If type() is specified call.addNamedOutputArgument(procedureParameterName, argumentFieldName, type()); // If jdbcType() is specified call.addNamedOutputArgument(procedureParameterName, argumentFieldName, jdbcType()); // If jdbcType() and jdbcTypeName() are specified call.addNamedOutputArgument(procedureParameterName, argumentFieldName, jdbcType(), jdbcTypeName()); // If no types are specified call.addNamedOutputArgument(procedureParameterName, argumentFieldName); // Then add the argument to the query. query.addArgument(argumentFieldName);

// ** For IN_OUT direction ** // If type() is specified call.addNamedInOutputArgument(procedureParameterName, argumentFieldName, argumentFieldName, type()); // If jdbcType() is specified call.addNamedInOutputArgument(procedureParameterName, argumentFieldName, argumentFieldName, jdbcType()); // If jdbcType() and jdbcTypeName() are specified call.addNamedInOutputArgument(procedureParameterName, argumentFieldName, argumentFieldName, jdbcType(), jdbcTypeName()); // If no types are specified call.addNamedInOutputArgument(procedureParameterName, argumentFieldName); // Then add the argument to the query. query.addArgument(argumentFieldName);

// ** For OUT_CURSOR direction ** call.useNamedCursorOutputAsResultSet(argumentFieldName);

// Process hints() // Same as @NamedQuery and @NamedNativeQuery

// And finally ... query.setCall(call); session.addQuery(query); {code}

  • Design*
  • Processed in ClassAccessor, during the same call from MetadataProcessor to process named query annotations.

Back to the top