4.3. Lifecycle Callbacks
Prev | Chapter 4. Entity | Next

## 4.3. Lifecycle Callbacks

It is often necessary to perform various actions at different stages of a persistent object's lifecycle. JPA includes a variety of callback methods for monitoring changes in the lifecycle of your persistent objects. These callbacks can be defined on the persistent classes themselves and on non-persistent listener classes.

### 4.3.1. Callback Methods

Every persistence event has a corresponding callback method marker. These markers are shared between persistent classes and their listeners. You can use these markers to designate a method for callback either by annotating that method or by listing the method in the XML mapping file for a given class. The lifecycle events and their corresponding method markers are:

- `PrePersist`: Methods marked with this annotation will be invoked before an object is persisted. This could be used for assigning primary key values to persistent objects. This is equivalent to the XML element tag `pre-persist`.

- `PostPersist`: Methods marked with this annotation will be invoked after an object has transitioned to the persistent state. You might want to use such methods to update a screen after a new row is added. This is equivalent to the XML element tag `post-persist`.

- `PostLoad`: Methods marked with this annotation will be invoked after all eagerly fetched fields of your class have been loaded from the datastore. No other persistent fields can be accessed in this method. This is equivalent to the XML element tag `post-load`.

  `PostLoad` is often used to initialize non-persistent fields whose values depend on the values of persistent fields, such as a complex datastructure.

- `PreUpdate`: Methods marked with this annotation will be invoked just before the persistent values in your objects are flushed to the datastore. This is equivalent to the XML element tag `pre-update`.

  `PreUpdate` is the complement to `PostLoad`. While methods marked with `PostLoad` are most often used to initialize non-persistent values from persistent data, methods annotated with `PreUpdate` is normally used to set persistent fields with information cached in non-persistent data.

- `PostUpdate`: Methods marked with this annotation will be invoked after changes to a given instance have been stored in the datastore. This is useful for clearing stale data cached at the application layer. This is equivalent to the XML element tag `post-update`.

- `PreRemove`: Methods marked with this annotation will be invoked before an object transactions to the deleted state. Access to persistent fields is valid within this method. You might use this method to cascade the deletion to related objects based on complex criteria, or to perform other cleanup. This is equivalent to the XML element tag `pre-remove`.

- `PostRemove`: Methods marked with this annotation will be invoked after an object has been marked for deletion. This is equivalent to the XML element tag `post-remove`.

### 4.3.2. Using Callback Methods

When declaring callback methods on a persistent class, any method may be used which takes no arguments and is not shared with any property access fields. Multiple events can be assigned to a single method as well.

Below is an example of how to declare callback methods on persistent classes:

    /**
     * Example persistent class declaring our entity listener.
     */
    @Entity
    public class Magazine
    {
        @Transient
        private byte[][] data;

        @ManyToMany
        private List<Photo> photos;

        @PostLoad
        public void convertPhotos ()
        {
            data = new byte[photos.size ()][];
            for (int i = 0; i < photos.size (); i++)
                data[i] = photos.get (i).toByteArray ();
        }

        @PreDelete
        public void logMagazineDeletion ()
        {
            getLog ().debug ("deleting magazine containing" + photos.size ()
                + " photos.");
        }
    }

In an XML mapping file, we can define the same methods without annotations:

    <entity class="Magazine">
        <pre-remove>logMagazineDeletion</pre-remove>
        <post-load>convertPhotos</post-load>
    </entity>

| Note
We fully explore persistence metadata annotations and XML in Chapter 5, Metadata.

### 4.3.3. Using Entity Listeners

Mixing lifecycle event code into your persistent classes is not always ideal. It is often more elegant to handle cross-cutting lifecycle events in a non-persistent listener class. JPA allows for this, requiring only that listener classes have a public no-arg constructor. Like persistent classes, your listener classes can consume any number of callbacks. The callback methods must take in a single `java.lang.Object` argument which represents the persistent object that triggered the event.

Entities can enumerate listeners using the `EntityListeners` annotation. This annotation takes an array of listener classes as its value.

Below is an example of how to declare an entity and its corresponding listener classes.

    /**
     * Example persistent class declaring our entity listener.
     */
    @Entity
    @EntityListeners({ MagazineLogger.class, ... })
    public class Magazine
    {
        // ... //
    }

    /**
     * Example entity listener.
     */
    public class MagazineLogger
    {
        @PostPersist
        public void logAddition (Object pc)
        {
            getLog ().debug ("Added new magazine:" + ((Magazine) pc).getTitle ());
        }

        @PreRemove
        public void logDeletion (Object pc)
        {
            getLog ().debug ("Removing from circulation:" +
                ((Magazine) pc).getTitle ());
        }
    }

In XML we define both the listeners and their callback methods this way:

    <entity class="Magazine">
        <entity-listeners>
            <entity-listener class="MagazineLogger">
                <post-persist>logAddition</post-persist>
                <pre-remove>logDeletion</pre-remove>
            </entity-listener>
        </entity-listeners>
    </entity>

### 4.3.4. Entity Listeners Hierarchy

Entity listener methods are invoked in a specific order when a given event is fired. So-called default listeners are invoked first: these are listeners which have been defined in a package annotation or in the root element of XML mapping files. Next, entity listeners are invoked in the order of the inheritance hierarchy, with superclass listeners being invoked before subclass listeners. Finally, if an entity has multiple listeners for the same event, the listeners are invoked in declaration order.

You can exclude default listeners, and listeners defined in superclasses, from the invocation chain via two class-level annotations:

- `ExcludeDefaultListeners`: This annotation indicates that no default listeners will be invoked for this class, or any of its subclasses. The XML equivalent is the empty `exclude-default-listeners` element.

- `ExcludeSuperclassListeners`: This annotation will cause Kodo to skip invoking any listeners declared in superclasses. The XML equivalent is empty the `exclude-superclass-listeners` element.

Prev | Up | Next
4.2. Entity Identity | Home | 4.4. Conclusions