Looked at many forums but haven\'t found answer...Simple stuff, method annotated with @PostLoad never gets invoked...added listener via @EntityListeners but problem remains.
The EJB3 @PostLoad
annotation doesn’t work when using a SessionFactory
based configuration, the post-load method will never get called.
Either use Hibernate's Interceptors or events or an EntityManager
based configuration.
Here's how to enable JPA's post op annotations in Hibernate 5.
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 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();
}
}
}
I've also been struggling to make this work on Hibernate4, using the session factory.
I found the solution quite simple but not documented anywhere using Integrator (Apparently the Hibernate4's way to deal with SessionFactory and listeners). The hibernate-entitymanager project provides an Integrator to add the required listeners to link EJB3's annotations @PostLoad, ... to the session factory. Just declare the class JpaIntegrator the SPI way.
Concretely, just add a file named org.hibernate.integrator.spi.Integrator in the META-INF/services folder and declare the implementation class in it (org.hibernate.ejb.event.JpaIntegrator)
Or enable the Hibernate event listeners that handle JPA callbacks. That is exactly what HEM does. How that is done is different between Hibernate 3 and Hibernate 4 (you never mentioned which version you are using); check the documentation for details on (a) the event listeners involved and (b) how to specify custom set of listeners.
There is also an alternative to hibernate's interceptors or events approach when using SessionFactory: implementing Lifecycle interface.