It is often useful for the application to react to certain events that occur inside the persistence mechanism. This allows the implementation of certain kinds of generic functionality, and extension of built-in functionality. The EJB3 specification provides two related mechanisms for this purpose.
A method of the entity may be designated as a callback method to receive notification of a particular entity life cycle event. Callbacks methods are annotated by a callback annotation. You can also define an entity listener class to be used instead of the callback methods defined directly inside the entity class. An entity listener is a stateless class with a no-arg constructor. An entity listener is defined by annotating the entity class with the @EntityListeners annotation:
@Entity @EntityListeners(class=Audit.class) public class Cat { @Id private Integer id; private String name; private Calendar dateOfBirth; @Transient private int age; private Date lastUpdate; //getters and setters /** * Set my transient property at load time based on a calculation, * note that a native Hibernate formula mapping is better for this purpose. */ @PostLoad public void calculateAge() { Calendar birth = new GregorianCalendar(); birth.setTime(dateOfBirth); Calendar now = new GregorianCalendar(); now.setTime( new Date() ); int adjust = 0; if ( now.get(Calendar.DAY_OF_YEAR) - birth.get(Calendar.DAY_OF_YEAR) < 0) { adjust = -1; } age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR) + adjust; } } public class LastUpdateListener { /** * automatic property set before any database persistence */ @PreUpdate @PrePersist public void setLastUpdate(Cat o) { o.setLastUpdate( new Date() ); } }
The same callback method or entity listener method can be annotated with more than one callback annotation. For a given entity, you cannot have two methods being annotated by the same callback annotation whether it is a callback method or an entity listener method. A callback method is a no-arg method with no return type and any arbitrary name. An entity listener has the signature public void <METHOD>(Object) where Object is of the actual entity type (note that Hibernate Entity Manager relaxed this constraint and allows Object of java.lang.Object type (allowing sharing of listeners accross several entities.)
A callback method can raise a RuntimeException. The current transaction, if any, must be rolled back. The following callbacks are defined:
Table 5.1. Callbacks
Type | Description |
---|---|
@PrePersist | Executed before the entity manager persist operation is actually executed or cascaded. This call is synchronous with the persist operation. |
@PreRemove | Executed before the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation. |
@PostPersist | Executed after the entity manager persist operation is actually executed or cascaded. This call is invoked after the database INSERT is executed. |
@PostRemove | Executed after the entity manager remove operation is actually executed or cascaded. This call is synchronous with the remove operation. |
@PreUpdate | Executed before the database UPDATE operation. |
@PostUpdate | Executed after the database UPDATE operation. |
@PostLoad | Eexecuted after an entity has been loaded into the current persistence context or an entity has been refreshed. |
A callback method must not invoke EntityManager or Query methods!
You can define several entity listeners per entity at different level of the hierarchy.You can also define several callbacks at different level of the hierarchy. But you cannot define two listeners for the same event in the same entity or the same entity listener.
When an event is raised, the listeners are executed in this order:
@EntityListeners for a given entity or superclass in the array order
Entity listeners for the superclasses (highest first)
Entity Listeners for the entity
Callbacks of the superclasses (highest first)
Callbacks of the entity
You can stop the entity listeners inheritance by using the @ExcludeSuperclassListeners, all superclasses @EntityListeners will then be ignored.