21

These jars are both new released and have the latest solutions for Java EE applications. But I have a problem on specifiying hibernate listeners in hibernate.cfg.xml.

Before spring 3.1.0, LocalSessionFactroyBean was holding an attribute that keeps eventlisteners. But with 3.1.0.release there is no eventlisteners map. Now I fail keeping the track of modal objects on saveorupdate, postload etc. because they are not configured by Spring. Do you have an idea to solve this issue?

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
asyard
  • 1,743
  • 5
  • 21
  • 43
  • My simple one file example of hibernate listeners for spring boot (spring-boot-starter 1.2.4.RELEASE) http://stackoverflow.com/a/31725844/975169 – Enginer Jul 30 '15 at 14:33

4 Answers4

37

I had the same frustrating problem. Hibernate 4 appears to have fundamentally changed the way you register for events and the Spring group has not yet caught up. Here's my annotation-based solution using an init method to register a listener:

@Component
public class HibernateEventWiring {

    @Autowired
    private SessionFactory sessionFactory;

    @Autowired
    private SomeHibernateListener listener;

    @PostConstruct
    public void registerListeners() {
        EventListenerRegistry registry = ((SessionFactoryImpl) sessionFactory).getServiceRegistry().getService(
        EventListenerRegistry.class);
        registry.getEventListenerGroup(EventType.POST_COMMIT_INSERT).appendListener(listener);
        registry.getEventListenerGroup(EventType.POST_COMMIT_UPDATE).appendListener(listener);
    }
}

An interceptor would be another fine approach, but support for interceptors was mistakenly dropped: https://jira.springsource.org/browse/SPR-8940

Vivin Paliath
  • 94,126
  • 40
  • 223
  • 295
nano
  • 434
  • 4
  • 4
  • Hi, yes, I figured out this solution. Works well temporarily. I hope it is not the lasest solution for hibernate-spring integration. Thank you. – asyard Jan 26 '12 at 08:26
  • Do you know how to set Listener to certain entity?? I see your implementation add listener to all entities. – idmitriev Apr 14 '15 at 14:00
  • Also very useful when not using spring. Unbelievable how complicated it is to register a pre-insert-listener (without using xml). Still can't believe the amount of code this took to set a "created" field automatically (on any entity with a certain interface). THIS IS JAVAAAA – NoUsername Jul 21 '15 at 21:36
  • See also for PreInsert and PreUpdate dates: http://stackoverflow.com/questions/5257709/how-to-autogenerate-created-or-modified-timestamp-field – Aliuk Mar 16 '17 at 11:27
14

The new approach is to use an Integrator to register the event listeners. Hibernate will now use service discovery for registering event listeners and here is how I got it to work using a maven archetype-webapp

create a file under META-INF/services (which should reside under your resources directory) called org.hibernate.integrator.spi.Integrator with all classes that implement the hibernate spi Interface, one line each. Short example below:

...

META-INF/services/org.hibernate.integrator.spi.Integrator

com.example.CustomIntegrator

com.example.CustomIntegrator

package com.example;

import ...;

public void CustomIntegrator implements Integrator {

    static final Logger logger = LoggerFactory.getLogger(CustomIntegrator.class);

    @Override
    public void integrate(Configuration configuration, SessionFactoryImplementor implementor, SessionFactoryServiceRegistry registry) {
        final EventListenerRegistry eventRegistry = registry.getService(EventListenerRegistry.class);

        logger.info("Registering event listeners");
        // you can add duplication strategory for duplicate registrations
        ...

        // prepend to register before or append to register after
        // this example will register a persist event listener
        eventRegistry.prependListeners(EventType.PERSIST, myListener);
        ...
    }

    ...

}

com.example.MyListener

package com.example;

import ...

public class MyListener implements PersistEventListener {

    static final Logger logger = LoggerFactory.getLogger(MyListener.class);

    public void onPersist(PersistEvent event) throws HibernateException {
        logger.debug("Entering MyListener");

        if(event.getObject() instanceof MyPersistableEntity) {
            MyPersistableEntity entity = (MyPersistableEntity) event.getObject();
            // do something with entity
            ...
        }
    }

    ...
}

Any entity that needs to have this event registered to it must implement MyPersistableEntity (not shown here)

David Kago
  • 326
  • 3
  • 3
  • Great answer for automatically updating the createdOn and lastUpdated timestamps. In addition I found this link useful. http://docs.jboss.org/hibernate/orm/4.1/devguide/en-US/html_single/#integrators – Rohit Banga Oct 16 '12 at 00:45
  • Note that there are significant issues with META-INF and Web app deployment (at least with Tomcat). In particular, you may need to make a separate .jar just to hold the services files :-\ See http://stackoverflow.com/questions/7692497/tomcat-wont-load-my-meta-inf-services-javax-servlet-servletcontainerinitializ – Luke Maurer Aug 18 '14 at 21:49
4

You might wanna check the Hibernate Ticket [1]: https://hibernate.onjira.com/browse/HHH-6945

The migration guide says:

hibernate.cfg.xml no longer supported as means of specifying listeners. New approach invloves using an org.hibernate.integrator.spi.Integrator which works based on "service discovery".

And you can get the complete instructions @ http://in.relation.to/Bloggers/EventListenerRegistration

The links in the ticket have some issue, use the following:

https://github.com/hibernate/hibernate-orm/blob/master/hibernate-envers/src/main/java/org/hibernate/envers/event/EnversIntegrator.java

https://github.com/hibernate/hibernate-orm/blob/master/hibernate-envers/src/main/resources/META-INF/services/org.hibernate.integrator.spi.Integrator

Hope this helps someone looking answers for this problem.

0

When appending custom Event listeners via the EventListenerRegistry class as mentioned in above responses one needs to make sure the default event listeners are removed. Otherwise if in your application there is onetomany mapping then "Hibernate exception: shared references to the collection: xyz" exception will be thrown