2010-05-10 19 views
18

Miró muchos foros pero no encontró respuesta ... Cosas simples, el método anotado con @PostLoad nunca se invoca ... se agregó oyente a través de @EntityListeners pero el problema persiste. Estoy usando la configuración basada en SessionFactory.Hibernate @PostLoad nunca se invoca

Respuesta

15

La anotación EJB3 @PostLoad no funciona cuando se utiliza una configuración basada en SessionFactory, nunca se llamará al método posterior a la carga.

O use la configuración basada en Interceptors or events de Hibernate o EntityManager.

+2

Las devoluciones de llamada puede trabajar absolutamente cuando se utiliza SessionFactory. Simplemente tiene que habilitar los propios detectores de eventos Hibernate. –

+0

Así es cómo habilitar los detectores de eventos: https://n1njahacks.wordpress.com/2016/10/07/jpa-callbacks-with-hibernates-sessionfactory-and-no-entitymanager/ –

9

También existe una alternativa al enfoque de interceptores o eventos de hibernate cuando se usa SessionFactory: implementación de la interfaz Lifecycle.

+3

Pero tenga cuidado con este error: https: //hibernate.onjira.com/browse/HHH-6043, que también es válida para Lifecycle.onLoad (se invoca antes de que se inicien las colecciones, hasta que se haya solucionado en Hibernate 4.1.8) – Jakub

1

O active los detectores de eventos de Hibernate que manejan devoluciones de llamada JPA. Eso es exactamente lo que HEM hace. Cómo se hace eso es diferente entre Hibernate 3 e Hibernate 4 (nunca mencionaste qué versión estás usando); revise la documentación para obtener detalles sobre (a) los oyentes del evento involucrados y (b) cómo especificar un conjunto de oyentes personalizado.

+0

Tal vez soy grueso, pero me está costando mucho encontrar cómo hazlo en la documentación de Hibernate 4. – David

2

También he estado luchando para hacer que esto funcione en Hibernate4, usando la fábrica de sesiones.

Encontré la solución bastante simple pero no documentada en ninguna parte usando Integrator (aparentemente la forma de Hibernate4 de tratar con SessionFactory y los oyentes). El proyecto hibernate-entitymanager proporciona un integrador para agregar los oyentes necesarios para vincular las anotaciones de EJB3 @PostLoad, ... a la fábrica de sesiones. Simplemente declare la clase JpaIntegratorSPI manera.

Concretamente, sólo tiene que añadir un archivo llamado org.hibernate.integrator.spi.Integrator en la carpeta/serviciosMETA-INF y declarar la clase de implementación en ella (org.hibernate.ejb.event.JpaIntegrator)

+0

Buena solución. FYI, a partir de Hibernate 4.3.5, el contenido del archivo debe ser "org.hibernate.jpa.event.spi.JpaIntegrator". –

+0

Esta es la solución que también fui, aunque descubrí que romperá las cascadas de Hibernate 5. Consulte mi respuesta a continuación para obtener una solución. –

+0

@Matt sé que es una pregunta muy antigua, pero ¿dónde debería encontrar este META-INF/Services? Solo puedo encontrarlo en la carpeta donde descargué hibernación y después de hacer cambios, todavía no funciona. –

3

así es como para permitir anotaciones post op de la APP en Hibernate 5.

de IntegratorServiceImpl Hibernate utiliza la API de java.util.ServiceLoader, por lo que podemos especificar una lista adicional de org.hibernate.integrator.spi.Integrator implementaciones queremos que el SessionFactory para usar.

Todo lo que tenemos que hacer es especificar un proveedor de servicios en META-INF/services/org.hibernate.integrator.spi.Integrator:

# This allows us to use JPA-style annotation on entities, such as @PostLoad 
our.custom.JpaAnnotationsIntegrator 

También tendrá que asegurarse de que ‘hibernate-entitymanager‘tarro de la versión adecuada está en la ruta de clases.

our.custom.JpaAnnotationsIntegrator (tomado de 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(); 
     } 
    } 
} 
Cuestiones relacionadas