6.4. Metadata Extensions
Prev | Chapter 6. Metadata | Next

## 6.4. Metadata Extensions

Kodo extends standard metadata to allow you to access advanced Kodo functionality. This section covers persistence metadata extensions; we discuss mapping metadata extensions in Section 7.9, “Mapping Extensions”. All metadata extensions are optional; Kodo will rely on its defaults when no explicit data is provided.

In JDO metadata, Kodo extensions are expresses with standard JDO `extension` elements. All Kodo extensions use a `vendor-name` of `kodo`. The next sections present a list of the available `class` and `field` element extension keys.

### 6.4.1. Class Extensions

Kodo recognizes the following class extensions:

#### 6.4.1.1. Fetch Groups

JDO standardizes fetch group definition with the the `fetch-group` XML mapping element. Fetch groups, however, are not part of the JPA standard. The `kodo.persistence.FetchGroups` and `kodo.persistence.FetchGroup` annotations allow you to define fetch groups in your JPA entities. Section 5.6, “Fetch Groups” discusses Kodo's support for fetch groups in general; see Section 5.6.1, “Custom Fetch Groups” for how to use these annotations in particular.

#### 6.4.1.2. Data Cache

Section 10.1, “Data Cache” examines caching in Kodo. Metadata extensions allow individual classes to override system caching defaults.

Kodo JPA defines the `kodo.persistence.DataCache` annotation for caching information. This annotation has the following properties:

- `boolean enabled`: Whether to cache data for instances of the class. Defaults to `true` for base classes, or the superclass value for subclasses. If you set this property to `false`, all other properties are ignored.

- `String name`: Place data for instances of the class in a named cache. By default, instance data is placed in the same cache as superclass data, or the default cache configured through the `kodo.DataCache` configuration property for base classes.

- `int timeout`: The number of milliseconds data for the class remains valid. Use -1 for no timeout. Defaults to the `kodo.DataCacheTimeout` property value.

Kodo JDO uses the `data-cache` and `data-cache-timeout` XML extension keys to specify class caching information. The `data-cache-timeout` key sets the number of milliseconds cached data for an instance remains valid. A value of -1 means never to expire instance data. This extension overrides the `kodo.DataCacheTimeout` configuration property.

The `data-cache` key accepts the following values:

- `true`: Use the default cache, as configured by the `kodo.DataCache` configuration property. This is the default when no extension is given, unless a superclass names a different cache.

- `false`: Data for instances of this class should not be cached.

- `<cache-name>`: Place data for instances of this class into the cache with name `<cache-name>`.

#### 6.4.1.3. Detached State

The Kodo enhancer may add a synthetic field to detachable classes to hold detached state (see Section 11.1.3, “Defining the Detached Object Graph” for details). You can instead declare your own detached state field or supress the creation of a detached state field altogether. In the latter case, your class must not use datastore identity, and should declare a version field to detect optimistic concurrency errors during detached modifications.

Kodo JPA defines the `kodo.persistence.DetachedState` annotation for controlling detached state. When used to annotate a class, `DetachedState` recognizes the following properties:

- `boolean enabled`: Set to false to suppress the use of detached state.

- `String fieldName`: Use this property to declare your own detached state field. The field must be of type `Object`. Typically this property is only used if the field is inherited from a non-persisted superclass. If the field is declared in your entity class, you will typically annotate the field directly, as described below.

If you declare your own detached state field, you can annotate that field with `DetachedState` directly, rather than placing the annotation at the class level and using the `fieldName` property. When placed on a field, `DetachedState` acts as a marker annotation; it does not recognize any properties. Your annotated field must be of type `Object`.

The JDO `detached-state-field` extension key names the `Object` field used to store an object's detached state information. Set this extension to the name of a field in your class, or to `false` to disable the use of detached state.

#### 6.4.1.4. Lock Groups

Kodo requires you to pre-declare subclass lock groups in the least-derived mapped class. The JPA `kodo.persistence.LockGroups` annotation accepts an array of lock group names. The JDO `lock-groups` XML extension key accepts a string of comma-separated lock group names. For details on lock groups, see Section 5.8.1, “Lock Groups and Subclasses”.

#### 6.4.1.5. Auditable

Reserved for future use.

### 6.4.2. Field Extensions

Kodo recognizes the following field extensions:

#### 6.4.2.1. Dependent

In a dependent relation, the referenced object is deleted whenever the owning object is deleted, or whenever the relation is severed by nulling or resetting the owning field. For example, if the `Magazine.coverArticle` field is marked dependent, then setting `Magazine.coverArticle` to a new `Article` instance will automatically delete the old `Article` stored in the field. Similarly, deleting a `Magazine` object will automatically delete its current cover `Article`. You can prevent an orphaned dependent object from being deleted by assigning it to another relation in the same transaction.

JDO standardizes support for dependent relations with the `dependent` attribute of the XML `field` element, and the `dependent-element`, `dependent-key`, and `dependent-value` attribues of the `collection` and `map` elements. Kodo JPA offers a family of marker annotations to denote dependent relations in JPA entities:

- `kodo.persistence.Dependent`: Marks a direct relation as dependent.

- `kodo.persistence.ElementDependent`: Marks the entity elements of a collection, array, or map field as dependent.

- `kodo.persistence.KeyDependent`: Marks the key entities in a map field as dependent.

#### 6.4.2.2. LRS

This boolean extension, denoted by the JPA `kodo.persistence.LRS` annotation, or the JDO `lrs` metadata extension key, indicates that a field should use Kodo's special large result set collection or map proxies. A complete description of large result set proxies is available in Section 5.5.4.2, “Large Result Set Proxies”.

#### 6.4.2.3. Order-By

The JPA Overview's Section 5.2.12, “Order By” describes JPA's `OrderBy` annotation for loading the elements of collection fields in a prescribed order. The JDO `order-by` metadata extension serves the same function. Ordering syntax is as follows:

    #element|<field name>[ asc|ascending|desc|descending][, ...]

The token `#element` represents the element value. Simple element types such as strings and primitive wrappers are sorted based on their natural ordering. If the collection holds persistent objects, its elements are sorted based on the natural ordering of the objects' primary key values. By substituting a field name for the `#element` token, you can order a collection of persistent objects by an arbitrary field in the related type, rather than by primary key.

The field name or `#element` token may be followed by the keywords `asc/ascending` or `desc/descending` in either all-upper or all-lower case to mandate ascending and descending order. If the direction is omitted, Kodo defaults to ascending order.

Note that the defined ordering is only applied when the collection is loaded from the datastore. It is not maintained by Kodo as you modify the collection in memory.

The following ordering string orders a collection by its element values in descending order:

    "#element desc"

The following ordering string orders a collection of `Author` objects by each author's last name in ascending order. If two last names are equal, the authors are ordered by first name in ascending order.

    "firstName, lastName"

#### 6.4.2.4. Inverse-Logical

This extension names the inverse field in a logical bidirectional relation. To create a logical bidrectional relation in Kodo JPA, use the `kodo.persistence.InverseLogical` annotation. To create a logical bidrectional relation in Kodo JDO, use the `inverse-logical` XML extension key. We discuss logical bidirectional relations and this extension in detail in Section 5.4, “Managed Inverses”.

#### 6.4.2.5. Lock Group

Lock groups allow for fine-grained optimistic locking concurrency. Use Kodo JPA's `kodo.persistence.LockGroup` annotation or Kodo JDO's `lock-group` extension key to name the lock group for a field. You can exclude a field from optimistic locking with a value of `none`. We discuss lock groups and this extension further in Section 5.8, “Lock Groups”.

#### 6.4.2.6. Read-Only

The read-only extension makes a field unwritable. The extension only applies to existing persistent objects; new object fields are always writeable.

To mark a field read-only in JPA metadata, set the `kodo.persistence.ReadOnly` annotation to a `kodo.persistence.UpdateAction` enum value. The `UpdateAction` enum includes:

- `UpdateAction.IGNORE`: Updates to the field are completely ignored. The field is not considered dirty. The new value will not even get stored in the Kodo data cache.

- `UpdateAction.RESTRICT`: Any attempt to change the field will result in an immediate exception.

To mark a field read-only in JDO metadata, set the `read-only` extension key to one of the following values:

- `ignore`: Updates to the field are completely ignored. The field is not considered dirty. The new value will not even get stored in the Kodo data cache.

- `restrict`: Any attempt to change the field will result in an immediate exception.

#### 6.4.2.7. Type

Kodo has three levels of support for relations:

1. Relations that hold a reference to an object of a concrete persistent class are supported by storing the primary key values of the related instance in the database.

2. Relations that hold a reference to an object of an unknown persistent class are supported by storing the stringified identity value of the related instance. This level of support does not allow queries across the relation.

3. Relations that hold an unknown object or interface. The only way to support these relations is to serialize their value to the database. This does not allow you to query the field, and is not very efficient.

Clearly, when you declare a field's type to be another persistence-capable class, Kodo uses level 1 support. By default, Kodo assumes that any interface-typed fields you declare will be implemented only by other persistent classes, and assigns interfaces level 2 support. The exception to this rule is the `java.io.Serializable` interface. If you declare a field to be of type `Serializable`, Kodo lumps it together with `java.lang.Object` fields and other non-interface, unrecognized field types, which are all assigned level 3 support.

With Kodo's type family of metadata extensions, you can control the level of support given to your unknown/interface-typed fields. Setting the value of this extension to `Entity` in JPA or `PersistenceCapable` in JDO indicates that the field value will always be some persistent object, and gives level 2 support. Setting the value of this extension to the class of a concrete persistent type is even better; it gives you level 1 support (just as if you had declared your field to be of that type in the first place). Setting this extension to `Object` uses level 3 support. This is useful when you have an interface relation that may not hold other persistent objects (recall that Kodo assumes interface fields will always hold persistent instances by default).

This extension is also used with Kodo's externalization feature, described in Section 5.5.5, “Externalization”.

Kodo JPA defines the following type annotations for field values, collection, array, and map elements, and map keys, respectively:

- `kodo.persistence.Type`

- `kodo.persistence.ElementType`

- `kodo.persistence.KeyType`

Kodo JDO defines the following type extension keys for field values, collection and array elements, map entry keys, and map entry values, respectively:

- `type`

- `element-type`

- `key-type`

- `value-type`

#### 6.4.2.8. Externalizer

The JPA `kodo.persistence.Externalizer` annotation or JDO `externalizer` extension key names a method to transform a field value into a value of another type. See Section 5.5.5, “Externalization” for details.

#### 6.4.2.9. Factory

The JPA `kodo.persistence.Factory` annotation or JDO `factory` extension key names a method to re-create a field value from its externalized form. See Section 5.5.5, “Externalization” for details.

#### 6.4.2.10. External Values

The JPA `kodo.persistence.ExternalValues` annotation or JDO `external-values` extension key declares values for transformation of simple fields to different constant values in the datastore. See Section 5.5.5.1, “External Values” for details.

### 6.4.3. Example

The following example shows you how to specify extensions in metadata.

Example 6.4. Kodo Metadata Extensions

JPA:

    import kodo.persistence.*;

    @Entity
    @DataCache(enabled=false)
    public class Magazine
    {
        @ManyToMany
        @LRS
        @LockGroup(LockGroup.NONE)
        private Collection<Subscriber> subscribers;

        @ExternalValues({"true=1", "false=2"})
        @Type(int.class)
        private boolean weekly;

        @PersistentCollection
        @OrderBy("#element DESC")
        private List<String> subtitles;

        ...
    }

JDO:

    <jdo>
        <package name="org.mag">
            <class name="Magazine">
                <extension vendor-name="kodo" key="data-cache" value="false"/>
                <field name="subscribers">
                    <collection element-type="Subscriber"/>
                    <extension vendor-name="kodo" key="lrs" value="true"/>
                    <extension vendor-name="kodo" key="lock-group" value="none"/>
                </field>
                <field name="weekly">
                    <extension vendor-name="kodo" key="external-values"
                        value="true=1,false=2"/>
                    <extension vendor-name="kodo" key="type" value="int"/>
                </field>
                <field name="subtitles">
                    <collection element-type="string"/>
                    <extension vendor-name="kodo" key="order-by"
                        value="#element desc"/>
                </field>
            </class>
        </package>
    </jdo>

Prev | Up | Next
6.3. Additional JPA Metadata | Home | Chapter 7. Mapping