Hibernate.orgCommunity Documentation

Chapter 13. Interceptors and events

Table of Contents

13.1. Interceptors
13.2. Native Event system
13.2.1. Hibernate declarative security
13.3. JPA Callbacks

It is useful for the application to react to certain events that occur inside Hibernate. This allows for the implementation of generic functionality and the extension of Hibernate functionality.

The org.hibernate.Interceptor interface provides callbacks from the session to the application, allowing the application to inspect and/or manipulate properties of a persistent object before it is saved, updated, deleted or loaded. One possible use for this is to track auditing information. For example, the following example shows an Interceptor implementation that automatically sets the createTimestamp property when an Auditable entity is created and updates the lastUpdateTimestamp property when an Auditable entity is updated.

Note

You can either implement Interceptor directly or extend org.hibernate.EmptyInterceptor.

An Interceptor can be either Session-scoped or SessionFactory-scoped.

A Session-scoped interceptor is specified when a session is opened.

Session session = sf.withOptions().interceptor( new AuditInterceptor() ).openSession();

A SessionFactory-scoped interceptor is registered with the Configuration object prior to building the SessionFactory. Unless a session is opened explicitly specifying the interceptor to use, the SessionFactory-scoped interceptor will be applied to all sessions opened from that SessionFactory. SessionFactory-scoped interceptors must be thread safe. Ensure that you do not store session-specific states, since multiple sessions will use this interceptor potentially concurrently.

SessionFactory sessionFactory = new Configuration()
		.setInterceptor( new AuditInterceptor() )
		...
		.buildSessionFactory();

If you have to react to particular events in the persistence layer, you can also use the Hibernate event architecture. The event system can be used in place of or in addition to interceptors.

Many methods of the Session interface correlate to an event type. The full range of defined event types is declared as enum values on org.hibernate.event.spi.EventType. When a request is made of one of these methods, the Session generates an appropriate event and passes it to the configured event listener(s) for that type. Applications are free to implement a customization of one of the listener interfaces (i.e., the LoadEvent is processed by the registered implementation of the LoadEventListener interface), in which case their implementation would be responsible for processing any load() requests made of the Session.

Note

See ??? for information on registering custom event listeners.

The listeners should be considered stateless; they are shared between requests, and should not save any state as instance variables.

A custom listener implements the appropriate interface for the event it wants to process and/or extend one of the convenience base classes (or even the default event listeners used by Hibernate out-of-the-box as these are declared non-final for this purpose). Here is an example of a custom load event listener:


Usually, declarative security in Hibernate applications is managed in a session facade layer. Hibernate allows certain actions to be permissioned via JACC, and authorized via JAAS. This is an optional functionality that is built on top of the event architecture.

First, you must configure the appropriate event listeners, to enable the use of JACC authorization. Again, see ??? for the details. Below is an example of an appropriate org.hibernate.integrator.spi.Integrator implementation for this purpose.

Example 13.2. JACC listener registration example

import org.hibernate.event.service.spi.DuplicationStrategy;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.secure.internal.JACCPreDeleteEventListener;
import org.hibernate.secure.internal.JACCPreInsertEventListener;
import org.hibernate.secure.internal.JACCPreLoadEventListener;
import org.hibernate.secure.internal.JACCPreUpdateEventListener;
import org.hibernate.secure.internal.JACCSecurityListener;

public class JaccEventListenerIntegrator implements Integrator {

	private static final DuplicationStrategy JACC_DUPLICATION_STRATEGY = new DuplicationStrategy() {
		@Override
		public boolean areMatch(Object listener, Object original) {
			return listener.getClass().equals( original.getClass() ) &&
					JACCSecurityListener.class.isInstance( original );
		}

		@Override
		public Action getAction() {
			return Action.KEEP_ORIGINAL;
		}
	};

	@Override
	@SuppressWarnings( {"unchecked"})
	public void integrate(
			Configuration configuration,
			SessionFactoryImplementor sessionFactory,
			SessionFactoryServiceRegistry serviceRegistry) {
		boolean isSecurityEnabled = configuration.getProperties().containsKey( AvailableSettings.JACC_ENABLED );
		if ( !isSecurityEnabled ) {
			return;
		}

		final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class );
		eventListenerRegistry.addDuplicationStrategy( JACC_DUPLICATION_STRATEGY );

		final String jaccContextId = configuration.getProperty( Environment.JACC_CONTEXTID );
		eventListenerRegistry.prependListeners( EventType.PRE_DELETE, new JACCPreDeleteEventListener(jaccContextId) );
		eventListenerRegistry.prependListeners( EventType.PRE_INSERT, new JACCPreInsertEventListener(jaccContextId) );
		eventListenerRegistry.prependListeners( EventType.PRE_UPDATE, new JACCPreUpdateEventListener(jaccContextId) );
		eventListenerRegistry.prependListeners( EventType.PRE_LOAD, new JACCPreLoadEventListener(jaccContextId) );
	}
}

You must also decide how to configure your JACC provider. Consult your JACC provider documentation.

JPA also defines a more limited set of callbacks through annotations.


There are 2 available approaches defined for specifying callback handling:

  • The first approach is to annotate methods on the entity itself to receive notification of particular entity life cycle event(s).

  • The second is to use a separate entity listener class. An entity listener is a stateless class with a no-arg constructor. The callback annotations are placed on a method of this class instead of the entity class. The entity listener class is then associated with the entity using the javax.persistence.EntityListeners annotation


These approaches can be mixed, meaning you can use both together.

Regardless of whether the callback method is defined on the entity or on an entity listener, it must have a void-return signature. The name of the method is irrelevant as it is the placement of the callback annotations that makes the method a callback. In the case of callback methods defined on the entity class, the method must additionally have a no-argument signature. For callback methods defined on an entity listener class, the method must have a single argument signature; the type of that argument can be either java.lang.Object (to facilitate attachment to multiple entities) or the specific entity type.

A callback method can throw a RuntimeException. If the callback method does throw a RuntimeException, then the current transaction, if any, must be rolled back.

A callback method must not invoke EntityManager or Query methods!

It is possible that multiple callback methods are defined for a particular lifecycle event. When that is the case, the defined order of execution is well defined by the JPA spec (specifically section 3.5.4):

  • Any default listeners associated with the entity are invoked first, in the order they were specified in the XML. See the javax.persistence.ExcludeDefaultListeners annotation.

  • Next, entity listener class callbacks associated with the entity hierarchy are invoked, in the order they are defined in the EntityListeners. If multiple classes in the entity hierarchy define entity listeners, the listeners defined for a superclass are invoked before the listeners defined for its subclasses. See the javax.persistence.ExcludeSuperclassListeners annotation.

  • Lastly, callback methods defined on the entity hierarchy are invoked. If a callback type is annotated on both an entity and one or more of its superclasses without method overriding, both would be called, the most general superclass first. An entity class is also allowed to override a callback method defined in a superclass in which case the super callback would not get invoked; the overriding method would get invoked provided it is annotated.