Table of contents
1.
Introduction
2.
Interceptor Classes
3.
Interceptor Lifecycles
4.
Hibernate Interceptors
4.1.
Implementing an Interceptor Interface
4.2.
Extending EmptyInterceptor
5.
Registering Interceptors
5.1.
With Session-scoped Interceptor
5.2.
With SessionFactory-scoped Interceptor
6.
Create Interceptors
7.
Overriding Interceptor Methods
8.
Create POJO Classes
9.
Create Database Tables
10.
Create Mapping Configuration File
11.
Frequently Asked Questions
11.1.
What is Hibernate code?
11.2.
In programming, what are interceptors?
11.3.
What is the process of hibernation?
12.
Conclusion
Last Updated: Mar 27, 2024
Medium

Hibernate Interceptors

Career growth poll
Do you think IIT Guwahati certified course can help you in your career?

Introduction

An interceptor is a function that is invoked by the framework BEFORE or AFTER an action invocation. Interceptors provide callbacks to specific Hibernate events. It aids in the implementation of AOP-style cross-cutting concerns as well as the extension of Hibernate functionality.

In this article, we will briefly discuss the hibernate interceptors, their implementation, types of registering interceptors, and the hibernate interceptors methods. We will also discuss hibernate interceptors through an employee class example. But before going onwards, let’s have a look at interceptor classes and interceptor lifecycles.

Interceptor Classes

The javax.interceptor keyword is used to designate interceptor classes. We can add comments to an interceptors, but adding comments to interceptor classes isn’t required. An interceptor class should have a public and no-argument constructor.

The target class can have any number of interceptor classes associated with it. The order in which the interceptor classes are defined determines which interceptor class is going to be invoked.

Interceptor Lifecycles

Interceptor classes follow the same lifecycle as their target classes. When a target class instance is created, a hibernate interceptor class instance is created for each declared interceptor class in the target class.

lifecycle

Before any @PostConstruct callbacks are invoked, the target class instance and all interceptor class instances are fully instantiated, and any @PreDestroy callbacks are invoked before the target class interceptors are destroyed.

Hibernate Interceptors

The Hibernate Interceptors is an interface that allows us to respond to Hibernate events.

These interceptors are registered as callbacks and serve as conduits for communication between Hibernate's session and the application. An application can intercept core Hibernate operations such as save, update and delete using such a callback.

Interceptors can be defined in two ways:

  1. implementing the org.hibernate.Interceptor interface
  2. extending the org.hibernate.EmptyInterceptor class

Implementing an Interceptor Interface

Using org.hibernate.Interceptor necessitates the implementation of approximately 14 supporting methods. OnLoad, onSave, onDelete, findDirty, and a few other methods are among them. It is also critical to ensure that any class that implements the Interceptor interface can be serialised (implements java.io.Serializable).

As an example, consider the following:

public class CustomInterceptorImpl implements Interceptor, Serializable {

    @Override
    public boolean onLoad(Object entity,
                              Object id,
                              Object[] currentState,
                              Object[] previousState,
                              Type[] types,
                              String[] propertyNames) 
      throws CallbackException {
        // ...
        return false;
    }

    // ...

    @Override
    public String onPrepareStatement(String line) {
        // ...   
        return line;
    }
}

 

If there are no special requirements, then extending the EmptyInterceptor class is advised and only overriding the required methods.

Extending EmptyInterceptor

The org.hibernate is being extended. The EmptyInterceptor class simplifies the definition of an interceptor. We only need to override the methods associated with the operation we want to intercept now.

For instance, we can define our CustomInterceptor as follows:

public class CustomInterceptor extends EmptyInterceptor {
}

 

And, if we want to intercept data-saving operations before they happen, we must override the onSave method:

@Override
public boolean onSave(Object entity,
                              Object id,
                              Object[] currentState,
                              Object[] previousState,
                              String[] propertyNames,
                              Type[] types) {
    
    if (entity instanceof User) {
        logger.info(((User) entity).toString());
    }
    return super.onSave(entity, id, currentState, previousState, propertyNames, types);
}

 

Look at the above program and observe how this implementation prints the entity if it is a User.

While it is possible to return a true or false value, it is best practice to allow onSave event propagation by invoking super.onSave().

Registering Interceptors

Hibernate interceptors can be Session-scoped or SessionFactory-scoped.

With Session-scoped Interceptor

If we only need to use the interceptor in a few places throughout the application, we can register it with the Session instances in those locations.

try (Session session = sessionFactory.withOptions()
        .interceptor(new AuditInterceptor()).openSession()) {
      session.getTransaction().begin();


      //...
}

With SessionFactory-scoped Interceptor

To enable the interceptor in all sessions created by the application, we can add it to the SessionFactory.

try {
  StandardServiceRegistry standardRegistry
      = new StandardServiceRegistryBuilder()
      .configure("hibernate-test.cfg.xml")
      .build();


  Metadata metadata = new MetadataSources(standardRegistry)
      .addAnnotatedClass(EmployeeEntity.class)
      .getMetadataBuilder()
      .build();


  sessionFactory = metadata
      .getSessionFactoryBuilder()
      .applyInterceptor(new AuditInterceptor())
      .build();


} catch (Throwable ex) {
  throw new ExceptionInInitializerError(ex);
}

Make sure that no state information is stored in the Hibernate Interceptors because multiple threads will share it. We can make the session context thread-local to make it even more secure against accidental uses.

Create Interceptors

In our example, we will extend EmptyInterceptor so that the Interceptor's method is called automatically when an Employee object is created or updated. More methods can be implemented based on your needs.

import java.io.Serializable;
import java.util.Iterator;
import java.util.Date;


import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
import org.hibernate.Transaction;


public class MyInterceptor extends EmptyInterceptor {
   private int updates;
   private int loads;
   private int creates;


   public void onDelete(Object entity,
                              Object id,
                              Object[] currentState,
                              Object[] previousState,
      Type[] types,
                              String[] propertyNames) 
                              
  {
       // do nothing
   }


   // This method will be called when the Employee object gets updated.
   public boolean onFlushDirty(Object entity,
                              Object id,
                              Object[] currentState,
                              Object[] previousState,
                              String[] propertyNames,
                              Type[] types) 
   {
      if ( entity instanceof Employee ) {
            System.out.println("Update Operation");
            return true; 
         }
      return false;
   }

   public boolean onLoad(Object entity,
                              Object id,
                              Object[] currentState,
                              Object[] previousState,
                              Type[] types,
                              String[] propertyNames) 
  {
         // do nothing
         return true;
   }
   
   // This method will be called when an Employee object gets created.
   public boolean onSave(Object entity,
                              Object id,
                              Object[] currentState,
                              Object[] previousState,
                              String[] propertyNames,
                              Type[] types) 
   {
      if ( entity instanceof Employee ) {
            System.out.println("Create Operation");
            return true; 
         }
      return false;
   }
   
   //called before committing to the database
   public void preFlush(Iterator iterator) {
      System.out.println("preFlush");
   }
   
   //called after committed into database
   public void postFlush(Iterator iterator) {
      System.out.println("postFlush");
   }
}

Overriding Interceptor Methods

The hibernate interceptors interface includes the following critical methods for intercepting specific events:

methods and description

Create POJO Classes

Let us now modify our first example, in which we used the EMPLOYEE table and Employee class to experiment with,

public class Employee {
   private int id;
   private String firstName; 
   private String lastName;   
   private int salary;  


   public Employee() {}
   
   public Employee(String firstname, String lastname, int salary) {
      this.firstName = firstname;
      this.lastName = lastname;
      this.salary = salary;
   }
   
// setting getter for id
   public int getId() {
      return id;
   }
   
// setting setter for id
   public void setId( int id ) {
      this.id = id;
   }
   
// setting getter for first name
   public String getFirstName() {
      return firstName;
   }
   
// setting setter for first name
   public void setFirstName( String first_name ) {
      this.firstName = first_name;
   }


// setting getter for last name   
   public String getLastName() {
      return lastName;
   }
   
// setting setter for last name
   public void setLastName( String last_name ) {
      this.lastName = last_name;
   }
 
// setting getter for salary  
   public int getSalary() {
      return salary;
   }
  
// setting setter for salary
   public void setSalary( int salary ) {
      this.salary = salary;
   }
}

Create Database Tables

Assuming you are willing to provide persistence, there would be one table for each object. Consider the objects that must be stored and retrieved in the RDBMS table below.

create table EMPLOYEE (
   id INT NOT NULL auto_increment,
   first_name VARCHAR(20) default NULL,
   last_name  VARCHAR(20) default NULL,
   salary     INT  default NULL,
   PRIMARY KEY (id)
);

Create Mapping Configuration File

This step involves creating a file that tells Hibernate how to map the specified class or classes to database tables.

<?xml version = "1.0" encoding = "utf-8"?>
<!DOCTYPE hibernate-mapping PUBLIC 
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 

<hibernate-mapping>
   <class name = "Employee" table = "EMPLOYEE">
      
      <meta attribute = "class-description">
         This class contains the employee detail. 
      </meta>
      
      <id name = "id" type = "int" column = "id">
         <generator class="native"/>
      </id>
      
      <property name = "firstName" column = "first_name" type = "string"/>
      <property name = "lastName" column = "last_name" type = "string"/>
      <property name = "salary" column = "salary" type = "int"/>
      
   </class>
</hibernate-mapping>

Frequently Asked Questions

What is Hibernate code?

Hibernate ORM (or Hibernate) is an object-relational mapping tool in Java. It provides a framework for mapping a relational database to an object-oriented domain model.

In programming, what are interceptors?

An interceptor is a software design pattern used in software development. When a software system or framework wants to offer a way to change or augment its normal processing cycle., we use an interceptor.

What is the process of hibernation?

Hibernate handles the mapping of Java classes to database tables using XML files without needing any code. Simple APIs for storing and retrieving Java objects directly from and from the database are provided. If the database or table changes, you only need to change the XML file properties.

Conclusion

In this article, we have extensively discussed the hibernate interceptors, their implementation, and how we extend them. We had also discussed registering interceptors with session scoped and with session factory scoped along with the hibernate interceptors methods. Afterward, we discussed hibernate interceptors through an employee class example. 

If you think this blog has helped you enhance your knowledge about the hibernate interceptors, and if you would like to learn more, check out our articles on hibernate architectureHB Generator classeshibernate sessions, and hibernate annotations. You can also refer to our guided path on the basics of java and many more on our Website.

Refer to our Guided Path on Coding Ninjas Studio to upskill yourself in Data Structures and AlgorithmsCompetitive ProgrammingJavaScriptSystem Design, and many more! If you want to test your competency in coding, you may check out the mock test series and participate in the contests hosted on Coding Ninjas Studio! 

But suppose you have just started your learning process and are looking for questions asked by tech giants like Amazon, Microsoft, Uber, etc. In that case, you must look at the problemsinterview experiences, and interview bundle for placement preparations.

Nevertheless, you may consider our paid courses to give your career an edge over others!

Happy Learning!

Live masterclass