Is it possible to integrate Spring managed Hibernate interceptors (http://docs.jboss.org/hibernate/orm/4.3/manual/en-US/html/ch14.html) in Spring Boot?
I'm using Spring Data JPA and Spring Data REST and need an Hibernate interceptor to act on an update of a particular field on an entity.
With standard JPA events it's not possible to get the old values, and hence I think I need to use the Hibernate interceptor.
Solution using Spring Boot 2
hibernate.session_factory.interceptor
you can usehibernate.ejb.interceptor
. Both properties work probably because of a backwards compatibility requirement.Why HibernatePropertiesCustomizer instead of application.properties
One suggested answer is to indicate your interceptor in the
spring.jpa.properties.hibernate.ejb.interceptor
property in application.properties/yml. This idea may not work if your interceptor is in a lib that will be used by several applications. You want your interceptor to be activated by just adding a dependency to your lib, without requiring each application to alter their application.properties.I ran into this same issue and wound up creating a small spring library to handle all of the setup.
https://github.com/teastman/spring-data-hibernate-event
If you're using Spring Boot, you just add the dependency:
Then add the annotation @HibernateEventListener to any method where the first parameter is the entity you want to listen to, and the second parameter is the Hibernate event that you want to listen for. I've also added the static util function getPropertyIndex to more easily get access to the specific property you want to check, but you can also just look at the raw Hibernate event.
I had a similar problem with a Spring 4.1.1, Hibernate 4.3.11 application - not Spring Boot.
Solution I found (after reading Hibernate EntityManagerFactoryBuilderImpl code) was that if you pass in a bean reference instead of a class name to
hibernate.ejb.interceptor
property of the entity manager definition, Hibernate will use that already instantiated bean.So in my entityManager definition in application context I had something like this:
The auditInterceptor is managed by Spring, therefore autowiring and other Spring-natured behaviours will be available to it.
Hello,
Give this a read: https://github.com/spring-projects/spring-boot/commit/59d5ed58428d8cb6c6d9fb723d0e334fe3e7d9be (use: HibernatePropertiesCustomizer interface)
OR
For simple Interceptor:
In order to configure this in your application you simply need to add: spring.jpa.properties.hibernate.ejb.interceptor = path.to.interceptor (in application.properties). The interceptor itself should be @Component.
As long as the interceptor doesn't actually use any beans. Otherwise it is a bit more complicated but I would be more than happy to offer the solution.
Don't forget to add in application-test.properties, an EmptyInterceptor to not use the logging system (or whatever you want to use it for) in tests (which wouldn't be very helpful).
Hope this was of use to you.
As a final note: always update your Spring / Hibernate versions (use the latest as possible) and you will see that most code will become redundant as newer versions try to reduce the configurations as much as possible.
I found another approach after researching two days about how integrate Hibernate Interceptors with Spring Data JPA, my solution is a hybrid between java configuration and xml configuration but this post was very useful. So my final solution was:
AuditLogInterceptor class:
Datasource Java Configuration:
Entity and Transaction Managers adding the Interceptor
persistence configuration file
There's not a particularly easy way to add a Hibernate interceptor that is also a Spring Bean but you can easily add an interceptor if it's manged entirely by Hibernate. To do that add the following to your
application.properties
:If you need the Interceptor to also be a bean you can create your own
LocalContainerEntityManagerFactoryBean
. TheEntityManagerFactoryBuilder
from Spring Boot 1.1.4 is a little too restrictive with the generic of the properties so you need cast to(Map)
, we'll look at fixing that for 1.2.