diff --git a/orm/hibernate-orm-6/pom.xml b/orm/hibernate-orm-6/pom.xml index eff7ebc4..17953fb3 100644 --- a/orm/hibernate-orm-6/pom.xml +++ b/orm/hibernate-orm-6/pom.xml @@ -38,6 +38,20 @@ org.hibernate.orm hibernate-core + + org.hibernate.orm + hibernate-hikaricp + + + io.opentelemetry.instrumentation + opentelemetry-jdbc + 2.14.0-alpha + + + org.apache.logging.log4j + log4j-slf4j-impl + 2.17.1 + com.h2database h2 diff --git a/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/MyConnectionProvider.java b/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/MyConnectionProvider.java new file mode 100644 index 00000000..d9ed589c --- /dev/null +++ b/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/MyConnectionProvider.java @@ -0,0 +1,152 @@ +package org.hibernate.bugs; + +import com.zaxxer.hikari.*; +import io.opentelemetry.api.*; +import io.opentelemetry.instrumentation.jdbc.datasource.*; +import org.hibernate.*; +import org.hibernate.dialect.*; +import org.hibernate.engine.jdbc.connections.internal.*; +import org.hibernate.engine.jdbc.connections.spi.*; +import org.hibernate.hikaricp.internal.*; +import org.hibernate.internal.log.*; +import org.hibernate.internal.util.*; +import org.hibernate.service.*; +import org.hibernate.service.spi.*; + +import javax.sql.*; +import java.sql.*; +import java.util.*; + +import static org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.allowJdbcMetadataAccess; + +/** + * Copy paste from {@link HikariCPConnectionProvider} because I couldn't find another + * way of wrapping a ds without having to parse the url and configuration ^^ + */ +public class MyConnectionProvider implements ConnectionProvider, Configurable, Stoppable { + + private static final long serialVersionUID = -9131625057941275711L; + private boolean isMetadataAccessAllowed = true; + + /** + * HikariCP configuration. + */ + private HikariConfig hcfg = null; + + /** + * HikariCP data source. + */ + private HikariDataSource hds = null; + + private DataSource ds = null; + + // ************************************************************************* + // Configurable + // ************************************************************************* + + @Override + public void configure(Map props) throws HibernateException { + try { + isMetadataAccessAllowed = allowJdbcMetadataAccess( props ); + + ConnectionInfoLogger.INSTANCE.configureConnectionPool( "HikariCP" ); + + hcfg = HikariConfigurationUtil.loadConfiguration( props ); + hds = new HikariDataSource( hcfg ); + + // this is the DataSource that will not always work as expected by hibernate + // see https://github.com/open-telemetry/opentelemetry-java-instrumentation/issues/13580 + ds = JdbcTelemetry.builder(OpenTelemetry.noop()) + .build() + .wrap(hds); + } + catch (Exception e) { + ConnectionInfoLogger.INSTANCE.unableToInstantiateConnectionPool( e ); + throw new HibernateException( e ); + } + } + + // ************************************************************************* + // ConnectionProvider + // ************************************************************************* + + @Override + public Connection getConnection() throws SQLException { + return ds != null ? ds.getConnection() : null; + } + + @Override + public void closeConnection(Connection connection) throws SQLException { + connection.close(); + } + + @Override + public boolean supportsAggressiveRelease() { + return false; + } + + @Override + public DatabaseConnectionInfo getDatabaseConnectionInfo(Dialect dialect) { + return new DatabaseConnectionInfoImpl( + hcfg.getJdbcUrl(), + // Attempt to resolve the driver name from the dialect, in case it wasn't explicitly set and access to + // the database metadata is allowed + !StringHelper.isBlank( hcfg.getDriverClassName() ) ? hcfg.getDriverClassName() : extractDriverNameFromMetadata(), + dialect.getVersion(), + Boolean.toString( hcfg.isAutoCommit() ), + hcfg.getTransactionIsolation(), + hcfg.getMinimumIdle(), + hcfg.getMaximumPoolSize() + ); + } + + private String extractDriverNameFromMetadata() { + if (isMetadataAccessAllowed) { + try ( Connection conn = getConnection() ) { + DatabaseMetaData dbmd = conn.getMetaData(); + return dbmd.getDriverName(); + } + catch (SQLException e) { + // Do nothing + } + } + return null; + } + + @Override + public boolean isUnwrappableAs(Class unwrapType) { + return ConnectionProvider.class.equals( unwrapType ) + || HikariCPConnectionProvider.class.isAssignableFrom( unwrapType ) + || DataSource.class.isAssignableFrom( unwrapType ); + } + + @Override + @SuppressWarnings("unchecked") + public T unwrap(Class unwrapType) { + if ( ConnectionProvider.class.equals( unwrapType ) + || HikariCPConnectionProvider.class.isAssignableFrom( unwrapType ) ) { + return (T) this; + } + else if ( HikariDataSource.class.isAssignableFrom( unwrapType ) ) { + return (T) hds; + } + else if ( DataSource.class.isAssignableFrom( unwrapType ) ) { + return (T) ds; + } + else { + throw new UnknownUnwrapTypeException( unwrapType ); + } + } + + // ************************************************************************* + // Stoppable + // ************************************************************************* + + @Override + public void stop() { + if ( hds != null ) { + ConnectionInfoLogger.INSTANCE.cleaningUpConnectionPool( "HikariCP" ); + hds.close(); + } + } +} diff --git a/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/ORMUnitTestCase.java b/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/ORMUnitTestCase.java index eefb7df4..05e9bb31 100644 --- a/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/ORMUnitTestCase.java +++ b/orm/hibernate-orm-6/src/test/java/org/hibernate/bugs/ORMUnitTestCase.java @@ -15,6 +15,7 @@ */ package org.hibernate.bugs; +import jakarta.persistence.*; import org.hibernate.cfg.AvailableSettings; import org.hibernate.testing.orm.junit.DomainModel; @@ -22,7 +23,9 @@ import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.Setting; -import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.*; + +import java.math.*; /** * This template demonstrates how to develop a test case for Hibernate ORM, using its built-in unit test framework. @@ -34,37 +37,44 @@ * submit it as a PR! */ @DomainModel( - annotatedClasses = { - // Add your entities here. - // Foo.class, - // Bar.class - }, - // If you use *.hbm.xml mappings, instead of annotations, add the mappings here. - xmlMappings = { - // "org/hibernate/test/Foo.hbm.xml", - // "org/hibernate/test/Bar.hbm.xml" - } + annotatedClasses = { + // Add your entities here. + ORMUnitTestCase.Foo.class, + // Bar.class + }, + // If you use *.hbm.xml mappings, instead of annotations, add the mappings here. + xmlMappings = { + // "org/hibernate/test/Foo.hbm.xml", + // "org/hibernate/test/Bar.hbm.xml" + } ) @ServiceRegistry( - // Add in any settings that are specific to your test. See resources/hibernate.properties for the defaults. - settings = { - // For your own convenience to see generated queries: - @Setting(name = AvailableSettings.SHOW_SQL, value = "true"), - @Setting(name = AvailableSettings.FORMAT_SQL, value = "true"), - // @Setting( name = AvailableSettings.GENERATE_STATISTICS, value = "true" ), + // Add in any settings that are specific to your test. See resources/hibernate.properties for the defaults. + settings = { + // For your own convenience to see generated queries: + @Setting(name = AvailableSettings.SHOW_SQL, value = "true"), + @Setting(name = AvailableSettings.FORMAT_SQL, value = "true"), + // @Setting( name = AvailableSettings.GENERATE_STATISTICS, value = "true" ), - // Add your own settings that are a part of your quarkus configuration: - // @Setting( name = AvailableSettings.SOME_CONFIGURATION_PROPERTY, value = "SOME_VALUE" ), - } + // Add your own settings that are a part of your quarkus configuration: + @Setting( name = AvailableSettings.CONNECTION_PROVIDER, value = "org.hibernate.bugs.MyConnectionProvider"), + } ) @SessionFactory class ORMUnitTestCase { - // Add your tests, using standard JUnit 5. - @Test - void hhh123Test(SessionFactoryScope scope) throws Exception { - scope.inTransaction( session -> { - // Do stuff... - } ); - } + // Add your tests, using standard JUnit 5. + @Test + void hhh123Test(SessionFactoryScope scope) throws Exception { + scope.inTransaction(session -> { + session.persist(new Foo()); + }); + } + + @Entity + static class Foo { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + } } diff --git a/orm/hibernate-orm-6/src/test/resources/log4j2.properties b/orm/hibernate-orm-6/src/test/resources/log4j2.properties index c55a2b0c..48e185ea 100644 --- a/orm/hibernate-orm-6/src/test/resources/log4j2.properties +++ b/orm/hibernate-orm-6/src/test/resources/log4j2.properties @@ -10,5 +10,8 @@ appender.console.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n # Root logger level rootLogger.level = info +logger.0.name = org.hibernate.resource.jdbc.internal.ResourceRegistryStandardImpl +logger.0.level = debug + # Root logger referring to console appender rootLogger.appenderRef.stdout.ref = consoleLogger \ No newline at end of file