Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support StatementInspector as @PersistenceUnitExtension managed bean #30640

Merged
merged 1 commit into from
Jan 27, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 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,26 @@ 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`.
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