Self-answered question
While migrating a Java Tomcat application from Hibernate 3 to Hibernate 5 (specifically version 5.4.24), we encountered an issue affecting our user creation form. The form, which previously functioned correctly, stopped working as expected.
The application in question doesn't use any additional frameworks for this module. We identified that the root cause of the issue was on the backend, directly related to the Hibernate migration.
After the migration, two specific issues arose:
Hibernate automatically added a new default listener called DefaultSaveOrUpdateListener. The order of Hibernate event listeners specified in our configuration file (hibernate.cfg.xml) was no longer being respected.
Solution
Use of Integrators
Upon diving deeper into the Hibernate documentation, I came across the concept of Integrators. This led me to realise that I could manually set the order of event listeners by implementing a custom Integrator.
Here is the steps of how we solved the issue:
Firstly, create a custom Integrator by implementing the Integrator interface. Make the necessary changes to order the listeners as you wish.
public class CustomSaveUpdateEventIntegrator implements Integrator {
private SaveOrUpdateEventListener[] getListeners() {
SaveOrUpdateEventListener[] listeners = new SaveOrUpdateEventListener[7];
listeners[6] = new CustomLastSaveOrUpdateEventListener(); // last listener (one before default)
// ... set the order of listeners in reverse as they are being prepended
listeners[0] = new CustomFirstSaveOrUpdateEventListener(); // first listener to be executed
return listeners;
}
@Override
public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory,
SessionFactoryServiceRegistry serviceRegistry) {
// Get existing event listeners
EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
// Get your custom listeners in correct order
SaveOrUpdateEventListener[] customListeners = getListeners();
// Register custom listeners
eventListenerRegistry.prependListeners(EventType.SAVE_UPDATE, listener);
}
}
In this code, I created a method getListeners() that manually sets the order of event listeners. Then, in the integrate() method, I added these listeners to the session factory's registry.
Then add Integrator Configuration file
To ensure that Hibernate picks up your custom Integrator, create a file named org.hibernate.integrator.spi.Integrator within your project's META-INF/services directory.
Place the fully-qualified name of your custom Integrator class inside this file. For example:
com.yourpackage.yourproject.hibernate.resources.CustomSaveUpdateEventIntegrator
Configuration Changes
Additionally, I made changes to the hibernate.cfg.xml to ensure this Integrator is used only for the specific session context in which we were experiencing issues.
Note: Hibernate still adds its own DefaultSaveOrUpdateListener, but the custom listeners now take precedence due to their specified order.