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

## 4. Metadata Extensions

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

### 4.1. Class Extensions

OpenJPA recognizes the following class extensions:

#### 4.1.1. Fetch Groups

The `org.apache.openjpa.persistence.FetchGroups` and `org.apache.openjpa.persistence.FetchGroup` annotations allow you to define fetch groups in your JPA entities. Section 7, “ Fetch Groups ” discusses OpenJPA's support for fetch groups in general; see Section 7.1, “ Custom Fetch Groups ” for how to use these annotations in particular.

#### 4.1.2. Data Cache

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

OpenJPA defines the `org.apache.openjpa.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.

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

#### 4.1.3. Detached State

The OpenJPA enhancer may add a synthetic field to detachable classes to hold detached state (see Section 1.3, “ Defining the Detached Object Graph ” for details). You can instead declare your own detached state field or suppress 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.

OpenJPA defines the `org.apache.openjpa.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`.

### 4.2. Field Extensions

OpenJPA recognizes the following field extensions:

#### 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`. (This latter processing is analogous to using JPA's CascadeType.REMOVE functionality as described in Section 2.9.1, “ Cascade Type ”.) You can prevent an orphaned dependent object from being automatically deleted by assigning it to another relation in the same transaction.

OpenJPA offers a family of marker annotations to denote dependent relations in JPA entities:

- `org.apache.openjpa.persistence.Dependent`: Marks a direct relation as dependent.

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

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

#### 4.2.2. Load Fetch Group

The `org.apache.openjpa.persistence.LoadFetchGroup` annotation specifies a field's load fetch group. Section 7, “ Fetch Groups ” discusses OpenJPA's support for fetch groups in general; see Section 7.1, “ Custom Fetch Groups ” for how to use this annotation in particular.

#### 4.2.3. LRS

This boolean extension, denoted by the OpenJPA `org.apache.openjpa.persistence.LRS` annotation, indicates that a field should use OpenJPA's special large result set collection or map proxies. A complete description of large result set proxies is available in Section 6.4.2, “ Large Result Set Proxies ”.

#### 4.2.4. Inverse-Logical

This extension names the inverse field in a logical bidirectional relation. To create a logical bidirectional relation in OpenJPA, use the `org.apache.openjpa.persistence.InverseLogical` annotation. We discuss logical bidirectional relations and this extension in detail in Section 5, “ Managed Inverses ”.

#### 4.2.5. 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 `org.apache.openjpa.persistence.ReadOnly` annotation to an `org.apache.openjpa.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 OpenJPA data cache.

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

#### 4.2.6. Type

OpenJPA 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, OpenJPA uses level 1 support. By default, OpenJPA 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`, OpenJPA lumps it together with `java.lang.Object` fields and other non-interface, unrecognized field types, which are all assigned level 3 support.

With OpenJPA'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` 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 OpenJPA assumes interface fields will always hold persistent instances by default).

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

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

- `org.apache.openjpa.persistence.Type`

- `org.apache.openjpa.persistence.ElementType`

- `org.apache.openjpa.persistence.KeyType`

#### 4.2.7. Externalizer

The OpenJPA `org.apache.openjpa.persistence.Externalizer` annotation names a method to transform a field value into a value of another type. See Section 6.5, “ Externalization ” for details.

#### 4.2.8. Factory

The OpenJPA `org.apache.openjpa.persistence.Factory` annotation names a method to re-create a field value from its externalized form. See Section 6.5, “ Externalization ” for details.

#### 4.2.9. External Values

The OpenJPA `org.apache.openjpa.persistence.ExternalValues` annotation declares values for transformation of simple fields to different constant values in the datastore. See Section 6.5.1, “ External Values ” for details.

### 4.3. Example

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

Example 6.4. OpenJPA Metadata Extensions

    import org.apache.openjpa.persistence.*;

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

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

        ...
    }

### 4.4. XML extensions

OpenJPA has extended the JPA 2.0 schema to include elements and attributes corresponding to OpenJPA extended metadata and mapping annotations. The schema are contained in 2 files: extendable-orm.xsd and openjpa-orm.xsd. The extendable-orm.xsd file provides copies of some of the JPA 2.0 schema elements with additional schema to make it extendable. The openjpa-orm.xsd file extends the extendable-orm.xsd with OpenJPA specific elements and attributes representing OpenJPA annotations. Currently, only a subset of annotations have actually been implemented, and some of those have been partially tested. The current status can be found by comments in the openjpa-orm.xsd schema file.

In order to use the OpenJPA extensions in your mapping file you must include the namespaces for these 2 new schemas as well as for the schema for JPA 2.0, as shown in the following example:

Example 6.5. OpenJPA Schema Extensions

    <entity-mappings xmlns="http://openjpa.apache.org/ns/orm/extendable"
        xmlns:openjpa="http://openjpa.apache.org/ns/orm"
        xmlns:orm="http://java.sun.com/xml/ns/persistence/orm"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        version="2.0">

        <entity class="org.apache.openjpa.persistence.jdbc.annotations.MultiColumnVersionPC"
            metadata-complete="true">
            <table name="MCV"/>
            <attributes>
                <id name="id">
                    <orm:generated-value/>
                </id>
                <basic name="id"/>
                <basic name="name"/>
            </attributes>
            <openjpa:entity version-strategy="version-numbers">
                <openjpa:version-columns>
                    <openjpa:version-column name="v1"/>
                    <openjpa:version-column name="v2"/>
                    <openjpa:version-column name="v3"
                        column-definition="FLOAT"
                        scale="3"
                        precision="10"/>
                </openjpa:version-columns>
            </openjpa:entity>
        </entity>

    </entity-mappings>

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