This post explains how to intercept hibernate create, read, update and delete operations, so that we can add our own logic that has to be performaned before CRUD operations. The different use case where we need to intercept these hibernate operations are as follows
1) Every entity in the applications has common fields for example last created and updated date time, updated user id etc that has to be set before the actual save is called. We can centralize the code in a common place which in this case will be our custom interceptor.
2) Adding code to log the details of the CRUD operations in a log file.
Hibernate helps us in intercepting those operations by providing ‘Interceptor’ interface and its default implementation ‘EmptyInterceptor’. We can either implement the interface or extend the default implementation to add our logic.
Below is the complete code explaining how to use hibernate interceptor.
MyHibernateInterceptor
import java.io.Serializable;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
public class MyHibernateInterceptor extends EmptyInterceptor {
@Override
public boolean onLoad(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
boolean result = super.onLoad(entity, id, state, propertyNames, types);
System.out.println("Loading: " + entity + ":" + id);
System.out.println("Printing properties");
for(String propertyName : propertyNames) {
System.out.println(propertyName);
}
System.out.println("Printing Types");
for(Type type : types) {
System.out.println(type.getName());
}
System.out.println("Printing state");
for(Object obj : state) {
System.out.println(obj);
}
System.out.println();
return result;
}
@Override
public void onDelete(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
super.onDelete(entity, id, state, propertyNames, types);
System.out.println("Deleting: " + entity + ":" + id);
System.out.println("Printing properties");
for(String propertyName : propertyNames) {
System.out.println(propertyName);
}
System.out.println("Printing Types");
for(Type type : types) {
System.out.println(type.getName());
}
System.out.println("Printing state");
for(Object obj : state) {
System.out.println(obj);
}
System.out.println();
}
@Override
public boolean onSave(Object entity, Serializable id, Object[] state,
String[] propertyNames, Type[] types) {
boolean result = super.onSave(entity, id, state, propertyNames, types);
System.out.println("Saving: " + entity + ":" + id);
System.out.println("Printing properties");
for(String propertyName : propertyNames) {
System.out.println(propertyName);
}
System.out.println("Printing Types");
for(Type type : types) {
System.out.println(type.getName());
}
System.out.println("Printing state");
for(Object obj : state) {
System.out.println(obj);
}
System.out.println();
return result;
}
@Override
public boolean onFlushDirty(Object entity, Serializable id,
Object[] currentState, Object[] previousState,
String[] propertyNames, Type[] types) {
boolean result = super.onFlushDirty(entity, id, currentState, previousState,
propertyNames, types);
System.out.println("Updating: " + entity + ":" + id);
System.out.println("Printing properties");
for(String propertyName : propertyNames) {
System.out.println(propertyName);
}
System.out.println("Printing Types");
for(Type type : types) {
System.out.println(type.getName());
}
System.out.println("Printing current state");
for(Object obj : currentState) {
System.out.println(obj);
}
System.out.println("Printing previous state");
for(Object obj : previousState) {
System.out.println(obj);
}
System.out.println();
return result;
}
}
HibernateUtil
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
public class HibernateUtil
{
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;
public static SessionFactory createSessionFactory()
{
if(sessionFactory == null) {
try
{
final StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build();
MyHibernateInterceptor myHibernateInterceptor = new MyHibernateInterceptor();
sessionFactory = new MetadataSources( registry ).buildMetadata().getSessionFactoryBuilder().applyInterceptor(myHibernateInterceptor).build();
}
catch(Throwable excep)
{
throw new ExceptionInInitializerError(excep);
}
}
return sessionFactory;
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
public static void shutdown()
{
sessionFactory.close();
StandardServiceRegistryBuilder.destroy(serviceRegistry);
}
}
Main Class
import model.Person;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
public class HibernateDemo3 {
public static void main(String[] args) {
SessionFactory sessionFactory = HibernateUtil.createSessionFactory();
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
Person person = new Person();
person.setName("name1");
person.setPhoneNumber(123456789);
Integer id = (Integer)session.save(person);
tx.commit();
session.close();
session = sessionFactory.openSession();
person = session.load(Person.class, id);
tx = session.beginTransaction();
person.setName("name2");
session.saveOrUpdate(person);
tx.commit();
session.close();
session = sessionFactory.openSession();
person = session.load(Person.class, id);
tx = session.beginTransaction();
session.delete(person);
tx.commit();
session.close();
HibernateUtil.shutdown();
}
}
Explanation
If we see the HibernateUtil code, an instance of MyHibernateInterceptor is created and added to the SessionFactory with the below code
MyHibernateInterceptor myHibernateInterceptor = new MyHibernateInterceptor();
sessionFactory = new MetadataSources( registry ).buildMetadata().getSessionFactoryBuilder().applyInterceptor(myHibernateInterceptor).build();
The Interceptor’s onFlushDirty is called when updating a modified object.
Note: The code in HibernateUtil will work for Hibernate 5 and above.
Output
Saving: model.Person@51e8e6e6:null
Printing properties
name
phoneNumber
Printing Types
string
integer
Printing state
name1
123456789
Loading: model.Person@346a361:2
Printing properties
name
phoneNumber
Printing Types
string
integer
Printing state
name1
123456789
Updating: model.Person@346a361:2
Printing properties
name
phoneNumber
Printing Types
string
integer
Printing current state
name2
123456789
Printing previous state
name1
123456789
Loading: model.Person@6256ac4f:2
Printing properties
name
phoneNumber
Printing Types
string
integer
Printing state
name2
123456789
Deleting: model.Person@6256ac4f:2
Printing properties
name
phoneNumber
Printing Types
string
integer
Printing state
name2
123456789