Skip to content

Commit

Permalink
Support StatementInspector as @PersistenceUnitExtension managed bean
Browse files Browse the repository at this point in the history
  • Loading branch information
gastaldi committed Jan 26, 2023
1 parent baa1c2f commit 07ffbb2
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 1 deletion.
25 changes: 25 additions & 0 deletions docs/src/main/asciidoc/hibernate-orm.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -1111,3 +1111,28 @@ In that case, the interceptor implementation doesn't need to be thread-safe.
Due to a limitation in Hibernate ORM itself,
`@PreDestroy` methods on `@Dependent`-scoped interceptors will never get called.
====


[[statement_inspectors]]
== Statement Inspectors

You can assign a `org.hibernate.engine.jdbc.spi.StatementInspector`
to your `SessionFactory` by simply defining a CDI bean with the appropriate qualifier:

[source,java]
----
@PersistenceUnitExtension // <1>
public class MyStatementInspector implements StatementInspector { // <2>
@Override
public String inspect(String sql) {
// ...
return sql;
}
}
----
<1> Annotate the statement inspector implementation with the `@PersistenceUnitExtension` qualifier
to tell Quarkus it should be used in the default persistence unit.
+
For <<multiple-persistence-units,named persistence units>>, use `@PersistenceUnitExtension("nameOfYourPU")`
<2> Implement `org.hibernate.engine.jdbc.spi.StatementInspector`.
<3> Implement methods as necessary.
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,6 @@ private static DotName createConstant(String fqcn) {
public static final DotName SESSION = createConstant("org.hibernate.Session");

public static final DotName INTERCEPTOR = createConstant("org.hibernate.Interceptor");
public static final DotName STATEMENT_INSPECTOR = createConstant("org.hibernate.resource.jdbc.spi.StatementInspector");

}
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ public class HibernateOrmCdiProcessor {
private static final Set<DotName> PERSISTENCE_UNIT_EXTENSION_VALID_TYPES = Set.of(
ClassNames.TENANT_RESOLVER,
ClassNames.TENANT_CONNECTION_RESOLVER,
ClassNames.INTERCEPTOR);
ClassNames.INTERCEPTOR,
ClassNames.STATEMENT_INSPECTOR);

@BuildStep
AnnotationsTransformerBuildItem convertJpaResourceAnnotationsToQualifier(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
package io.quarkus.hibernate.orm.jdbc;

import static org.assertj.core.api.Assertions.assertThat;

import java.util.ArrayList;
import java.util.List;

import javax.enterprise.event.Observes;
import javax.inject.Inject;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.transaction.UserTransaction;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.RegisterExtension;

import io.quarkus.hibernate.orm.PersistenceUnitExtension;
import io.quarkus.runtime.StartupEvent;
import io.quarkus.test.QuarkusUnitTest;

public class ApplicationScopedStatementInspectorTest {

@RegisterExtension
static QuarkusUnitTest runner = new QuarkusUnitTest()
.withApplicationRoot((jar) -> jar
.addClass(MyEntity.class)
.addClass(ApplicationStatementInspector.class))
.withConfigurationResource("application.properties");

@Inject
SessionFactory sessionFactory;

@Inject
Session session;

@Inject
UserTransaction transaction;

public void initData(@Observes StartupEvent event) throws Exception {
transaction.begin();
for (int i = 0; i < 3; i++) {
MyEntity entity = new MyEntity(i);
session.persist(entity);
}
transaction.commit();
}

@BeforeEach
public void clearStatementInspector() {
ApplicationStatementInspector.statements.clear();
}

@Test
public void testStatementInspectorIsLoaded() throws Exception {
transaction.begin();
session.find(MyEntity.class, 0);
transaction.commit();
assertThat(ApplicationStatementInspector.statements).hasSize(1);
}

@Entity(name = "myentity")
@Table
public static class MyEntity {

@Id
public Integer id;

public MyEntity() {
}

public MyEntity(int id) {
this.id = id;
}
}

@PersistenceUnitExtension // @ApplicationScoped is the default
public static class ApplicationStatementInspector implements StatementInspector {

static List<String> statements = new ArrayList<>();

@Override
public String inspect(String sql) {
statements.add(sql);
return sql;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import org.hibernate.internal.SessionFactoryImpl;
import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.resource.jdbc.spi.StatementInspector;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.tool.schema.spi.CommandAcceptanceException;
Expand Down Expand Up @@ -184,6 +185,12 @@ protected void populate(String persistenceUnitName, SessionFactoryOptionsBuilder
if (!interceptorInstance.isUnsatisfied()) {
options.applyStatelessInterceptorSupplier(interceptorInstance::get);
}

InjectableInstance<StatementInspector> statementInspectorInstance = PersistenceUnitUtil
.singleExtensionInstanceForPersistenceUnit(StatementInspector.class, persistenceUnitName);
if (!statementInspectorInstance.isUnsatisfied()) {
options.applyStatementInspector(statementInspectorInstance.get());
}
}

private static class ServiceRegistryCloser implements SessionFactoryObserver {
Expand Down

0 comments on commit 07ffbb2

Please sign in to comment.