Hibernate 5 - Interceptor example

Posted on November 11, 2017


In Hibernate, interceptors are used to inspect the changes in entity’s property values before they are written and after they are read from a database.

You can use the Hibernate interceptor to perform the various operations such as logging, auditing, profiling etc.

In Hibernate, an interceptor can be either Session-scoped or SessionFactory-scoped.

Session-scoped interceptors are used when a Session is opened. The following code snippet shows the how to add an interceptor to a Session.

Session session = HibernateUtil.getSessionFactory()
	.withOptions()
	.interceptor(new LoggingInterceptor())
	.openSession();

SessionFactory-scoped or global interceptors are used when SessionFactory is configured and these interceptors will be applied to applied to all Session opened from that SessionFactory. The following code snippet shows the how to add an interceptor to a SessionFactory.

SessionFactory sessionFactory = metadata.getSessionFactoryBuilder()
	.applyInterceptor(new LoggingInterceptor())
	.build();

The following example demonstrates how to implement a custom interceptor to log the SQL queries and entity’s property values when an entity is saved.

Tools and technologies used for this application are - 

  • Hibernate ORM 5.2.12.Final
  • Log4j 2.8.2
  • JavaSE 1.8
  • MySQL Server 5.7.12
  • Eclipse Oxygen.1

Project structure

Final project structure of our application will look like as follows.

 hibernate5-interceptor-example.png

Related - How to create a maven project in eclipse

Jar dependencies

Open pom.xml file of your maven project, add the dependencies below.

<dependencies>
  <dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <version>5.2.12.Final</version>
  </dependency>
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>6.0.6</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.8.2</version>
  </dependency>
  <dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.8.2</version>
  </dependency>
</dependencies>

 Entity class

Create a simple @Entity class as follows.

Book.java

package com.boraji.tutorial.hibernate.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Book {
   
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   private long id;

   private String title;
   private String author;

   //Getter and Setter methods
   
   public String toString() {
      return "Book [id=" + id + ", title=" + title + ", author=" + author + "]";
   }
}

 

Hibernate Interceptor

To create an interceptor, you can either implement the org.hibernate.Interceptor or extend the org.hibernate.EmptyInterceptor class.

The Interceptor interface contains various methods as follows.

MethodsDescription
onSave()

Called before an object is saved.

onLoad()

Called just before an object is initialized.

onDelete()

Called before an object is deleted.

preFlush()

Called before a flush.

postFlush()

Called after a flush.

For all available methods in Interceptor, you can refer-  Hibernate JavaDoc.

Create a LoggingInterceptor by extending the EmptyInterceptor class and override the onSave() method to log an entity when it is saved.

LoggingInterceptor.java

package com.boraji.tutorial.hibernate.interceptor;

import java.io.Serializable;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;

import com.boraji.tutorial.hibernate.entity.Book;

public class LoggingInterceptor extends EmptyInterceptor {

   private static final long serialVersionUID = 1L;
   // Define a static logger
   private static Logger logger = LogManager.getLogger(LoggingInterceptor.class);

   @Override
   public boolean onSave(Object entity, Serializable id, Object[] state,
            String[] propertyNames, Type[] types) {
      logger.info("onSave method is called.");
      if (entity instanceof Book) {
         Book book = (Book) entity;
         logger.info(book.toString());
      }
      return super.onSave(entity, id, state, propertyNames, types);
   }
   // Logging SQL statement
   @Override
   public String onPrepareStatement(String sql) {
      logger.info(sql);
      return super.onPrepareStatement(sql);
   }

}

Hibernate Utility class

Create a helper class HibernateUtil to bootstrap hibernate.

Map the Book entity using the #MetadataSources.addAnnotatedClass() method.

HibernateUtil.java

package com.boraji.tutorial.hibernate;

import java.util.HashMap;
import java.util.Map;

import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Environment;

import com.boraji.tutorial.hibernate.entity.Book;

public class HibernateUtil {

   private static StandardServiceRegistry registry;
   private static SessionFactory sessionFactory;

   public static SessionFactory getSessionFactory() {
      if (sessionFactory == null) {
         try {
            StandardServiceRegistryBuilder registryBuilder
                  = new StandardServiceRegistryBuilder();

            Map<String, Object> settings = new HashMap<>();
            settings.put(Environment.DRIVER, "com.mysql.cj.jdbc.Driver");
            settings.put(Environment.URL, "jdbc:mysql://localhost:3306/BORAJI?useSSL=false");
            settings.put(Environment.USER, "root");
            settings.put(Environment.PASS, "admin");
            settings.put(Environment.HBM2DDL_AUTO, "update");

            registryBuilder.applySettings(settings);
            registry = registryBuilder.build();

            MetadataSources sources = new MetadataSources(registry)
                  .addAnnotatedClass(Book.class);

            Metadata metadata = sources.getMetadataBuilder().build();

            //  To apply logging Interceptor using session factory
            sessionFactory = metadata.getSessionFactoryBuilder()
//                .applyInterceptor(new LoggingInterceptor())
                  .build();
         } catch (Exception e) {
            if (registry != null) {
               StandardServiceRegistryBuilder.destroy(registry);
            }
            e.printStackTrace();
         }
      }
      return sessionFactory;
   }

   public static void shutdown() {
      if (registry != null) {
         StandardServiceRegistryBuilder.destroy(registry);
      }
   }
}

If you want to use the LoggerInterceptor as a SessionFactory-scoped interceptor, just uncomment the lines from HibernateUtil class.

Hibernate Interceptor logging

In this example, we will use the log4j 2 API to log the overridden methods of a custom interceptor.

Create a log4j2.xml file under src/main/resources folder and write the following code in it.

log4j2.xml

<?xml version="1.0" encoding="UTF-8"?>
<Configuration>
  <Appenders>
    <!-- Console Appender -->
    <Console name="Console" target="SYSTEM_OUT">
      <PatternLayout
        pattern="%d{yyyy-MMM-dd HH:mm:ss a}  %-5level %logger{36} - %msg%n" />
    </Console>

  </Appenders>
  <Loggers>
    <!-- Logging interceptor in hibernate -->
    <Logger name="com.boraji.tutorial.hibernate.interceptor"
      level="trace" additivity="false">
      <AppenderRef ref="Console" />
    </Logger>

    <Root level="error">
      <AppenderRef ref="Console" />
    </Root>
  </Loggers>
</Configuration>

 

Run Application

Create the MainApp class to test the custom interceptor class.

You need to specify the LoggerInterceptor when a Session is opened as follows.

MainApp.java

package com.boraji.tutorial.hibernate;

import org.hibernate.Session;
import org.hibernate.Transaction;

import com.boraji.tutorial.hibernate.entity.Book;
import com.boraji.tutorial.hibernate.interceptor.LoggingInterceptor;


public class MainApp {

   public static void main(String[] args) {

      Session session = null;
      Transaction transaction = null;
      try {
         session = HibernateUtil.getSessionFactory()
               .withOptions()
               .interceptor(new LoggingInterceptor()) // add interceptor to Session
               .openSession();
         
         transaction = session.getTransaction();
         transaction.begin();
         
         Book book=new Book();
         book.setTitle("Java 8: A Beginner's Guide");
         book.setAuthor("Herbert Schildt");
         session.save(book);
         
         transaction.commit();
      } catch (Exception e) {
         if (transaction != null) {
            transaction.rollback();
         }
         e.printStackTrace();
      } finally {
         if (session != null) {
            session.close();
         }
      }
      HibernateUtil.shutdown();
   }

}

After executing the MainApp, the output of your program will look like as follows.

hibernate5-interceptor-example_01.png

Download Sources