3

https://docs.jboss.org/hibernate/orm/5.2/javadocs/org/hibernate/Interceptor.html says that onPrepareStatement(String sql) is Deprecated. Supply a StatementInspector instead, if you wish to inspect and alter SQL statements.

But I am not clear how I can configure StatementInspector in Hibernate at application level (i don't want to set it at each hibernate session level).

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
gosachin1
  • 61
  • 1
  • 8

5 Answers5

7

The best way to register a StatementInspector is to use the hibernate.session_factory.statement_inspector configuration property.

This way, it does not matter whether you are bootstrapping Hibernate using JPA (e.g. Spring Data JPA) or native Hibernate (e.g. Spring with HibernateTranscationManager and LocalSessionFactoryBean).

So, you can to provide the hibernate.session_factory.statement_inspector via the persistence.xml JPA configuration file:

<property
    name="hibernate.session_factory.statement_inspector"
    value="com.vladmihalcea.book.hpjp.hibernate.logging.inspector.SqlCommentStatementInspector"
/>

Or, you can also set the hibernate.session_factory.statement_inspector programmatically if you're using Spring:

@Bean
public LocalSessionFactoryBean sessionFactory() {
    LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
    sessionFactory.setDataSource(dataSource());
    sessionFactory.setPackagesToScan({
        "com.vladmihalcea.books.high.performance.java.persistence"
    });
    sessionFactory.setHibernateProperties(hibernateProperties());

    return sessionFactory;
}

@Bean
public PlatformTransactionManager hibernateTransactionManager() {
    HibernateTransactionManager transactionManager
      = new HibernateTransactionManager();
    transactionManager.setSessionFactory(sessionFactory().getObject());
    return transactionManager;
}

private final Properties hibernateProperties() {
    Properties hibernateProperties = new Properties();
    hibernateProperties.setProperty(
      "hibernate.session_factory.statement_inspector", 
      SqlCommentStatementInspector.class
    );
    hibernateProperties.setProperty(
      "hibernate.dialect", 
      "org.hibernate.dialect.H2Dialect"
    );

    return hibernateProperties;
}

Notice that the hibernate.session_factory.statement_inspector setting can take either a String representing he fully-qualified class implementing the StatementInspector interface, a Class<? extends StatementInspector> or a StatementInspector object reference.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
4

Don't do like that )

You need only two things:

  1. Add property to persistence.xml:

property name="hibernate.session_factory.statement_inspector" value="full-qualified class name"

  1. Write your listener class by implementing interface org.hibernate.resource.jdbc.spi.StatementInspector.

Profit!

empyros
  • 121
  • 5
1

You can use HibernatePropertiesCustomizer in Spring

@Configuration
public class HibernateConfig {

    @Bean
    public HibernatePropertiesCustomizer configureStatementInspector() {
        return (properties) -> properties.put(AvailableSettings.STATEMENT_INSPECTOR, (StatementInspector) sql -> {
            // figure out what to return
            return sql;
        });
    }
}
Pawel Zieminski
  • 439
  • 3
  • 8
0

In order to get this to work, you have to bootstrap Hibernate. To do this:

In your main class, find your EntityManagerFactory instance. It probably looks something like this:

public static final EntityManagerFactory EMPFAC = Persistence.createEntityManagerFactory("jpa")

Leave that line for now. Above it, add the following:

private static StandardServiceRegistryBuilder servReg = new StandardServiceRegistryBuilder();
static {
    //Do this for every property in persistence.xml
    servReg.applySetting("hibernate.connection.url", "jdbc://myurl://www.example.org");
}

Add a servReg.applySetting() for every property in persistence.xml. Then, add this below it:

private static MetadataSources sources = new MetadataSources(servReg.build());
static {
    // Do this for every pojo with JPA annotations
    sources.addAnnotatedClass(Pojo.class);
}

Add a sources.addAnnotatedClass() for every JPA-annotated pojo in your application. Almost done here. Now create a class that implements StatementInspector like so:

public class Inspector implements StatementInspector {

    private static final long serialVersionUID = 5545844969759630544L;

   @Override
   public String inspect(String select) {
       // modify string here
       return select;
   }
}

Finally, go back to your main application class, and, underneath the static block where you registered your pojos, add the following:

public static final SessionFactory EMPFAC = sources.buildMetadata().getSessionFactoryBuilder().applyStatementInspector(new Inspector()).build();

Now you can go back to persistence.xml and delete the property declarations there. If you haven't already, also delete your public static final EntityManager declaration (you've replaced it with the SessionFactory).

EDIT: You can actually delete persistence.xml and your application should still work fine.

All set!

0

Things haven't changed much - basically some things were renamed, so from the old "Interceptor" code-examples you find online, you just need to adapt these name-changes. If you manually build your SessionFactory (as I do), you can do it like this:

public class MyInspector implements StatementInspector {
   @Override
   public String inspect(String sql) {
       System.out.println(sql); // or whatever you want to do
       return sql;
   }
}

Then, while setting up your SessionFactory, you insert it very much the same way you inserted the Interceptor before

Configuration config = new Configuration();
config.setProperty("hibernate.connection.username", "myusername");
// ...
config.addAnnotatedClass(SomeClass.class);
// ...
config.setStatementInspector(new MyInspector()); // !!!!!!!!!!!!!!
SessionFactory mySessionFactory = config.buildSessionFactory();
// do something with the session factory

see setInterceptor in 6.1 in comparison to setStatementInspector in 6.2