I wanted to use JPA callback annotations, such as @PostLoad
and @PostUpdate, but realized that those JPA annotations do not work, unless Hibernate is configured to use a JPA EnityManager. My project uses Hibernate’s SessionFactory, so these annotations are not available to me out of the box.
So, how do we configure Hibernate to get the best of both worlds? Here’s how I did it in Hibernate 5. Hibernate 4 can use a very similar approach, but the code would be slightly different (just grab it from org.hibernate.jpa.event.spi.JpaIntegrator)
Luckily, Hibernate’s IntegratorServiceImpl uses the java.util.ServiceLoader API, so we can specify an additional list of org.hibernate.integrator.spi.Integrator implementations we want the SessionFactory to use.
All we need to do is specify a service provider for org.hibernate.integrator.spi.Integrator in:
META-INF/services/org.hibernate.integrator.spi.Integrator:
# This allows us to use JPA-style annotation on entities, such as @PostLoad our.custom.JpaAnnotationsIntegrator
You will also need to ensure that ‘hibernate-entitymanager‘ jar of the appropriate version is on your classpath.
our.custom.JpaAnnotationsIntegrator (taken from org.hibernate.jpa.event.spi.JpaIntegrator):
package our.custom; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.boot.Metadata; import org.hibernate.boot.internal.MetadataImpl; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; import org.hibernate.integrator.spi.Integrator; import org.hibernate.jpa.event.internal.core.JpaPostDeleteEventListener; import org.hibernate.jpa.event.internal.core.JpaPostInsertEventListener; import org.hibernate.jpa.event.internal.core.JpaPostLoadEventListener; import org.hibernate.jpa.event.internal.core.JpaPostUpdateEventListener; import org.hibernate.jpa.event.internal.jpa.CallbackBuilderLegacyImpl; import org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl; import org.hibernate.jpa.event.spi.jpa.CallbackBuilder; import org.hibernate.jpa.event.spi.jpa.ListenerFactory; import org.hibernate.jpa.event.spi.jpa.ListenerFactoryBuilder; import org.hibernate.mapping.PersistentClass; import org.hibernate.service.spi.SessionFactoryServiceRegistry; /** * This integrator allows us to use JPA-style post op annotations on Hibernate entities. * * This integrator is loaded by <code>org.hibernate.integrator.internal.IntegratorServiceImpl</code> from * <code>META-INF/services/org.hibernate.integrator.spi.Integrator</code> file. * * <b>Note</b>: This code is lifted directly from <code>org.hibernate.jpa.event.spi.JpaIntegrator</code> * * @author Val Blant */ public class JpaAnnotationsIntegrator implements Integrator { private ListenerFactory jpaListenerFactory; private CallbackBuilder callbackBuilder; private CallbackRegistryImpl callbackRegistry; @Override public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService( EventListenerRegistry.class ); this.callbackRegistry = new CallbackRegistryImpl(); // post op listeners eventListenerRegistry.prependListeners( EventType.POST_DELETE, new JpaPostDeleteEventListener(callbackRegistry) ); eventListenerRegistry.prependListeners( EventType.POST_INSERT, new JpaPostInsertEventListener(callbackRegistry) ); eventListenerRegistry.prependListeners( EventType.POST_LOAD, new JpaPostLoadEventListener(callbackRegistry) ); eventListenerRegistry.prependListeners( EventType.POST_UPDATE, new JpaPostUpdateEventListener(callbackRegistry) ); // handle JPA "entity listener classes"... final ReflectionManager reflectionManager = ( (MetadataImpl) metadata ) .getMetadataBuildingOptions() .getReflectionManager(); this.jpaListenerFactory = ListenerFactoryBuilder.buildListenerFactory( sessionFactory.getSessionFactoryOptions() ); this.callbackBuilder = new CallbackBuilderLegacyImpl( jpaListenerFactory, reflectionManager ); for ( PersistentClass persistentClass : metadata.getEntityBindings() ) { if ( persistentClass.getClassName() == null ) { // we can have non java class persisted by hibernate continue; } callbackBuilder.buildCallbacksForEntity( persistentClass.getClassName(), callbackRegistry ); } } @Override public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) { if ( callbackRegistry != null ) { callbackRegistry.release(); } if ( callbackBuilder != null ) { callbackBuilder.release(); } if ( jpaListenerFactory != null ) { jpaListenerFactory.release(); } } }