Working with an interceptor

As we know, in the hibernate persistent lifecycle, a particular object travels from state to state, from transient, persistent, to detached. During processing, it may commit or roll back before it reaches the last state. Sometimes, we need to perform some additional tasks such as cleanup, log or some operations on the object between different states of the persistent life cycle. To perform such activities, hibernate provides a useful and pluggable feature called interceptor.

Interceptor, as the name suggests, is used to intercept any operation. Interceptors apply hooks inside the logic. In hibernate, we have some built-in interceptors that help us intercept our logic.

Generally, an interceptor is used to log monitor data that is input and to validate it. You can also change or overwrite it at runtime. Let's take a look at the next example.

Getting ready

In this recipe, we will discuss the use of a basic interceptor and some methods of intercepting. Here, we will try to save the employee object and capturing the log while saving an object.

Creating the classes

For this recipe, we will create an Employee class:

Source file: Employee.java

@Entity
@Table(name = "employee")
public class Employee {

  @Id
  @GeneratedValue
  private long id;

  @Column(name = "name")
  private String name;

  // getters ans setters
}

Creating the tables

Use the following table script if the hibernate.hbm2ddl.auto configuration property is not set to create:

Use the following script to create the employee table:

CREATE TABLE `employee` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
);

How to do it…

First of all, we need to create an interceptor class that extends EmptyInterceptor, which implements the org.hibernate.Interceptor interface. Update the following code:

Code

Source file: CustomInterceptor.java

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;
public class CustomInterceptor extends EmptyInterceptor {

  /* Line 3 */ public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[] types) {
    System.out.println("On Save");
    System.out.println("entity: " + entity);
    System.out.println("id: " + id);
    System.out.println("state: " + Arrays.toString(state));
    System.out.println("propertyNames: " + Arrays.toString(propertyNames));
    System.out.println("types: " + Arrays.toString(types));
    return false;
  }

  /* Line 13 */ public void preFlush(Iterator iterator) {
    System.out.println("

Pre flush");
    while (iterator.hasNext()) {
      System.out.println(iterator.next());
    }
  }

  /* Line 20 */ public void postFlush(Iterator iterator) {
    System.out.println("

Post flush");
    while (iterator.hasNext()) {
      System.out.println(iterator.next());
    }
  }
}

Source file: InterceptorTest.java

/* Line 1 */ CustomInterceptor interceptor = new CustomInterceptor();
/* Line 2 */ Session session = sessionFactory.withOptions().interceptor(interceptor).openSession();
/* Line 3 */ Transaction tx = null;
/* Line 4 */ tx = session.beginTransaction();

/* Line 6 */ Employee employee = new Employee();
/* Line 7 */ employee.setName("Vishal");
/* Line 8 */ session.saveOrUpdate(employee);

/* Line 9 */ tx.commit();
/* Line 10 */ session.close();
/* Line 11 */ sessionFactoy.close();

Output:

On Save
entity: Employee: 
  Id: 0
  Name: Vishal
id: null
state: [Vishal]
propertyNames: [name]
types: [org.hibernate.type.StringType@4abd7e7c]
Hibernate: insert into employee (name) values (?)


Pre flush
Employee: 
  Id: 1
  Name: Vishal


Post flush
Employee: 
  Id: 1
  Name: Vishal

How it works…

In the previous section, we created two different Java source files. the first one is CustomInterceptor.java, which overrides some methods of the EmptyInterceptor superclass, and the other is the InterceptorTest.java executable class, which shows the code to test the mechanism.

Now, we will consider the code in detail.

The working of InterceptorTest.java

This is an executable class and contains the main method.

In Line 1, we created the object of the CustomInterceptor class.

Line 2 shows how to provide options to SessionFactory on runtime; builder design patterns are used to provide the interceptor to the session. The withOptions() method returns the instance of SessionBuilder. On top of it, we set an interceptor that is an instance of CustomInterceptor using the interceptor() method and then opened a new session.

The code from Line 3 onward creates an employee object and saves it within the boundary of the transaction.

The working of CustomInterceptor.java

Here, we extended the EmptyInterceptor class and implemented the three methods.

The working of onSave Method

The onSave method is called before the object is saved to the database. Constructor of onSave is shown in the following code:

boolean onSave(Object entity,
               Serializable id,
               Object[] state,
               String[] propertyNames,
               Type[] types)
               throws CallbackException

The arguments passed are as follows:

  • Object entity: This shows the requested object for save. Here, the employee is passed, so it shows the details of the employee. One important thing shown here is that the object is not saved while processing this method, so the id fields are set to 0.
  • Serializable id: This shows the serializable id. Here, it is null because we are saving the object.
  • Object[] state: This contains the values to be saved; here, vishal, as we have only one field in the POJO.
  • String[] propertyNames: This contains the property name with respect to the state field; here, the name field, where the value of this field is stored in the state object.
  • Type[] types: This field contains the datatype of all the fields that are sent to save.

The working of preFlush Method

Another of the methods we implemented is preFlush. This method is called after commit is completed and just before flush is started. Use of preFlush() is shown in the following code:

  /* Line 13 */ public void preFlush(Iterator iterator) {
    System.out.println("

Pre flush");
    while (iterator.hasNext()) {
      System.out.println(iterator.next());
    }
  }

In the output, you will find id=1, which was 0 in the onSave() method, because the object is saved to the database. The argument iterator returns the object whose id is going to be flushed out.

The working of postFlush Method

The last of the three methods is postFlush. This method is called after commit is completed and just before flush is completed. Use of postFlush() is shown in the following code:

  /* Line 20 */ public void postFlush(Iterator iterator) {
    System.out.println("

Post flush");
    while (iterator.hasNext()) {
      System.out.println(iterator.next());
    }
  }
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.133.156.251