From 6146809af23a4c1daf5ecf1ceaf188f06ecd17d0 Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Mon, 2 Jul 2018 10:48:56 +0300 Subject: [PATCH] HHH-12749 - Avoid setting the isolation level to the same value in C3P0ConnectionProvider --- hibernate-c3p0/hibernate-c3p0.gradle | 2 + .../c3p0/internal/C3P0ConnectionProvider.java | 2 +- .../c3p0/C3P0DefaultIsolationLevelTest.java | 100 ++++++++ .../c3p0/C3P0DifferentIsolationLevelTest.java | 101 ++++++++ .../c3p0/C3P0ProxyConnectionProvider.java | 65 ++++++ .../org.mockito.plugins.MockMaker | 1 + .../functional/OracleFollowOnLockingTest.java | 2 +- .../test/distinct/SelectDistinctHqlTest.java | 2 +- .../test/id/SequenceGeneratorTest.java | 2 +- .../PessimisticWriteLockTimeoutTest.java | 2 +- .../jdbc/autocommit/H2SkipAutoCommitTest.java | 2 +- .../autocommit/MySQLSkipAutoCommitTest.java | 2 +- .../autocommit/OracleSkipAutoCommitTest.java | 3 +- .../PostgreSQLSkipAutoCommitTest.java | 3 +- .../SQLServerSkipAutoCommitTest.java | 3 +- .../hibernate/test/util/ReflectionUtil.java | 159 ------------- .../jdbc/SQLStatementInterceptor.java | 2 +- .../testing/util/ReflectionUtil.java | 221 ++++++++++++++++++ 18 files changed, 501 insertions(+), 173 deletions(-) create mode 100644 hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DefaultIsolationLevelTest.java create mode 100644 hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DifferentIsolationLevelTest.java create mode 100644 hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java create mode 100644 hibernate-c3p0/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/util/ReflectionUtil.java rename {hibernate-core/src/test/java/org/hibernate/test/util => hibernate-testing/src/main/java/org/hibernate/testing}/jdbc/SQLStatementInterceptor.java (95%) create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/util/ReflectionUtil.java diff --git a/hibernate-c3p0/hibernate-c3p0.gradle b/hibernate-c3p0/hibernate-c3p0.gradle index 0fcc0500ad..6da5cfb6a2 100644 --- a/hibernate-c3p0/hibernate-c3p0.gradle +++ b/hibernate-c3p0/hibernate-c3p0.gradle @@ -9,6 +9,8 @@ dependencies { compile( libraries.c3p0 ) testCompile project( ':hibernate-testing' ) + testCompile( libraries.mockito ) + testCompile( libraries.mockito_inline ) testCompile( libraries.validator ) { // for test runtime diff --git a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java index 043026021b..0ffecfcc63 100644 --- a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java +++ b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java @@ -71,7 +71,7 @@ public class C3P0ConnectionProvider @SuppressWarnings("UnnecessaryUnboxing") public Connection getConnection() throws SQLException { final Connection c = ds.getConnection(); - if ( isolation != null ) { + if ( isolation != null && !isolation.equals( c.getTransactionIsolation() ) ) { c.setTransactionIsolation( isolation.intValue() ); } if ( c.getAutoCommit() != autocommit ) { diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DefaultIsolationLevelTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DefaultIsolationLevelTest.java new file mode 100644 index 0000000000..37ca6529ed --- /dev/null +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DefaultIsolationLevelTest.java @@ -0,0 +1,100 @@ +package org.hibernate.test.c3p0; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.H2Dialect; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; + +/** + * @author Vlad Mihalcea + */ +@TestForIssue(jiraKey = "HHH-12749") +@RequiresDialect(H2Dialect.class) +public class C3P0DefaultIsolationLevelTest extends + BaseNonConfigCoreFunctionalTestCase { + + private C3P0ProxyConnectionProvider connectionProvider; + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { + sqlStatementInterceptor = new SQLStatementInterceptor( sfb ); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + }; + } + + @Override + protected void addSettings(Map settings) { + connectionProvider = new C3P0ProxyConnectionProvider(); + settings.put( AvailableSettings.CONNECTION_PROVIDER, connectionProvider ); + settings.put( AvailableSettings.ISOLATION, "READ_COMMITTED" ); + } + + @Test + public void testStoredProcedureOutParameter() throws SQLException { + clearSpies(); + + doInHibernate( this::sessionFactory, session -> { + Person person = new Person(); + person.id = 1L; + person.name = "Vlad Mihalcea"; + + session.persist( person ); + } ); + + assertEquals( 1, sqlStatementInterceptor.getSqlQueries().size() ); + assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).toLowerCase().startsWith( "insert into" ) ); + Connection connectionSpy = connectionProvider.getConnectionSpyMap().keySet().iterator().next(); + verify( connectionSpy, never() ).setTransactionIsolation( Connection.TRANSACTION_READ_COMMITTED ); + + clearSpies(); + + doInHibernate( this::sessionFactory, session -> { + Person person = session.find( Person.class, 1L ); + + assertEquals( "Vlad Mihalcea", person.name ); + } ); + + assertEquals( 1, sqlStatementInterceptor.getSqlQueries().size() ); + assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).toLowerCase().startsWith( "select" ) ); + connectionSpy = connectionProvider.getConnectionSpyMap().keySet().iterator().next(); + verify( connectionSpy, never() ).setTransactionIsolation( Connection.TRANSACTION_READ_COMMITTED ); + } + + private void clearSpies() { + sqlStatementInterceptor.getSqlQueries().clear(); + connectionProvider.clear(); + } + + @Entity(name = "Person") + public static class Person { + + @Id + private Long id; + + private String name; + } + +} diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DifferentIsolationLevelTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DifferentIsolationLevelTest.java new file mode 100644 index 0000000000..e8560d3e74 --- /dev/null +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DifferentIsolationLevelTest.java @@ -0,0 +1,101 @@ +package org.hibernate.test.c3p0; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Map; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.H2Dialect; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * @author Vlad Mihalcea + */ +@TestForIssue(jiraKey = "HHH-12749") +@RequiresDialect(H2Dialect.class) +public class C3P0DifferentIsolationLevelTest extends + BaseNonConfigCoreFunctionalTestCase { + + private C3P0ProxyConnectionProvider connectionProvider; + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { + sqlStatementInterceptor = new SQLStatementInterceptor( sfb ); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + }; + } + + @Override + protected void addSettings(Map settings) { + connectionProvider = new C3P0ProxyConnectionProvider(); + settings.put( AvailableSettings.CONNECTION_PROVIDER, connectionProvider ); + settings.put( AvailableSettings.ISOLATION, "REPEATABLE_READ" ); + } + + @Test + public void testStoredProcedureOutParameter() throws SQLException { + clearSpies(); + + doInHibernate( this::sessionFactory, session -> { + Person person = new Person(); + person.id = 1L; + person.name = "Vlad Mihalcea"; + + session.persist( person ); + } ); + + assertEquals( 1, sqlStatementInterceptor.getSqlQueries().size() ); + assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).toLowerCase().startsWith( "insert into" ) ); + Connection connectionSpy = connectionProvider.getConnectionSpyMap().keySet().iterator().next(); + verify( connectionSpy, times(1) ).setTransactionIsolation( Connection.TRANSACTION_REPEATABLE_READ ); + + clearSpies(); + + doInHibernate( this::sessionFactory, session -> { + Person person = session.find( Person.class, 1L ); + + assertEquals( "Vlad Mihalcea", person.name ); + } ); + + assertEquals( 1, sqlStatementInterceptor.getSqlQueries().size() ); + assertTrue( sqlStatementInterceptor.getSqlQueries().get( 0 ).toLowerCase().startsWith( "select" ) ); + connectionSpy = connectionProvider.getConnectionSpyMap().keySet().iterator().next(); + verify( connectionSpy, times(1) ).setTransactionIsolation( Connection.TRANSACTION_REPEATABLE_READ ); + } + + private void clearSpies() { + sqlStatementInterceptor.getSqlQueries().clear(); + connectionProvider.clear(); + } + + @Entity(name = "Person") + public static class Person { + + @Id + private Long id; + + private String name; + } + +} diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java new file mode 100644 index 0000000000..7e19668a89 --- /dev/null +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java @@ -0,0 +1,65 @@ +package org.hibernate.test.c3p0; + +import java.sql.Connection; +import java.sql.SQLException; +import java.util.HashMap; +import java.util.Map; +import javax.sql.DataSource; + +import org.hibernate.c3p0.internal.C3P0ConnectionProvider; + +import org.hibernate.testing.util.ReflectionUtil; + +import org.mockito.MockSettings; +import org.mockito.Mockito; + +/** + * @author Vlad Mihalcea + */ +public class C3P0ProxyConnectionProvider extends C3P0ConnectionProvider { + + private static final MockSettings VERIFIEABLE_MOCK_SETTINGS = Mockito.withSettings() + .defaultAnswer( org.mockito.Answers.CALLS_REAL_METHODS ); + + private final Map connectionSpyMap = new HashMap<>(); + + private static T spy(T subject) { + return Mockito.mock( (Class) subject.getClass(), VERIFIEABLE_MOCK_SETTINGS.spiedInstance( subject ) ); + } + + @Override + public void configure(Map props) { + super.configure( props ); + DataSource ds = unwrap( DataSource.class ); + DataSource dataSource = spy( ds ); + + try { + Mockito.doAnswer( invocation -> { + Connection connection = (Connection) invocation.callRealMethod(); + Connection connectionSpy = spy( connection ); + connectionSpyMap.put( connectionSpy, connection ); + return connectionSpy; + } ).when( dataSource ).getConnection(); + } + catch (SQLException e) { + throw new IllegalStateException( e ); + } + + ReflectionUtil.setField( C3P0ConnectionProvider.class.cast( this ), "ds", dataSource ); + } + + @Override + public void closeConnection(Connection conn) throws SQLException { + Connection originalConnection = connectionSpyMap.get( conn ); + + super.closeConnection( originalConnection != null ? originalConnection : conn ); + } + + public Map getConnectionSpyMap() { + return connectionSpyMap; + } + + public void clear() { + connectionSpyMap.clear(); + } +} diff --git a/hibernate-c3p0/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker b/hibernate-c3p0/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 0000000000..ca6ee9cea8 --- /dev/null +++ b/hibernate-c3p0/src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleFollowOnLockingTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleFollowOnLockingTest.java index 7139517a74..f19539eee7 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleFollowOnLockingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/OracleFollowOnLockingTest.java @@ -28,7 +28,7 @@ import org.hibernate.exception.SQLGrammarException; import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.hibernate.test.util.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.junit.Before; import org.junit.Test; diff --git a/hibernate-core/src/test/java/org/hibernate/test/distinct/SelectDistinctHqlTest.java b/hibernate-core/src/test/java/org/hibernate/test/distinct/SelectDistinctHqlTest.java index 25a64f4d18..df13035c24 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/distinct/SelectDistinctHqlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/distinct/SelectDistinctHqlTest.java @@ -20,7 +20,7 @@ import org.hibernate.jpa.QueryHints; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.hibernate.test.util.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.junit.Test; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; diff --git a/hibernate-core/src/test/java/org/hibernate/test/id/SequenceGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/test/id/SequenceGeneratorTest.java index 86e5bd236f..67258c4551 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/id/SequenceGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/id/SequenceGeneratorTest.java @@ -19,7 +19,7 @@ import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.hibernate.test.util.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.junit.Test; import static org.junit.Assert.assertTrue; diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteLockTimeoutTest.java b/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteLockTimeoutTest.java index 195d118d59..d86a0d52f1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteLockTimeoutTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/locking/PessimisticWriteLockTimeoutTest.java @@ -11,7 +11,7 @@ import org.hibernate.dialect.SQLServer2005Dialect; import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.hibernate.test.util.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.junit.Before; import org.junit.Test; diff --git a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/H2SkipAutoCommitTest.java b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/H2SkipAutoCommitTest.java index 14a541cacf..cb10242769 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/H2SkipAutoCommitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/H2SkipAutoCommitTest.java @@ -13,7 +13,7 @@ import org.hibernate.cfg.Environment; import org.hibernate.dialect.H2Dialect; import org.hibernate.testing.RequiresDialect; -import org.hibernate.test.util.ReflectionUtil; +import org.hibernate.testing.util.ReflectionUtil; /** * @author Vlad Mihalcea diff --git a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/MySQLSkipAutoCommitTest.java b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/MySQLSkipAutoCommitTest.java index 1b43cf6a98..4fcc9c4545 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/MySQLSkipAutoCommitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/MySQLSkipAutoCommitTest.java @@ -14,7 +14,7 @@ import org.hibernate.dialect.MariaDBDialect; import org.hibernate.dialect.MySQLDialect; import org.hibernate.testing.RequiresDialect; -import org.hibernate.test.util.ReflectionUtil; +import org.hibernate.testing.util.ReflectionUtil; /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/OracleSkipAutoCommitTest.java b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/OracleSkipAutoCommitTest.java index ad582f2b0f..e6a7bc195d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/OracleSkipAutoCommitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/OracleSkipAutoCommitTest.java @@ -10,11 +10,10 @@ import javax.sql.DataSource; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; -import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.Oracle8iDialect; import org.hibernate.testing.RequiresDialect; -import org.hibernate.test.util.ReflectionUtil; +import org.hibernate.testing.util.ReflectionUtil; /** * @author Vlad Mihalcea diff --git a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/PostgreSQLSkipAutoCommitTest.java b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/PostgreSQLSkipAutoCommitTest.java index ec537dd0f4..35e2794b9c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/PostgreSQLSkipAutoCommitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/PostgreSQLSkipAutoCommitTest.java @@ -10,11 +10,10 @@ import javax.sql.DataSource; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; -import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.testing.RequiresDialect; -import org.hibernate.test.util.ReflectionUtil; +import org.hibernate.testing.util.ReflectionUtil; /** * @author Vlad Mihalcea diff --git a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/SQLServerSkipAutoCommitTest.java b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/SQLServerSkipAutoCommitTest.java index e036d56bb9..e68f4842e6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/SQLServerSkipAutoCommitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/resource/transaction/jdbc/autocommit/SQLServerSkipAutoCommitTest.java @@ -10,11 +10,10 @@ import javax.sql.DataSource; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; -import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.testing.RequiresDialect; -import org.hibernate.test.util.ReflectionUtil; +import org.hibernate.testing.util.ReflectionUtil; /** * @author Vlad Mihalcea diff --git a/hibernate-core/src/test/java/org/hibernate/test/util/ReflectionUtil.java b/hibernate-core/src/test/java/org/hibernate/test/util/ReflectionUtil.java deleted file mode 100644 index 93cd0a84c6..0000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/util/ReflectionUtil.java +++ /dev/null @@ -1,159 +0,0 @@ -package org.hibernate.test.util; - -import java.lang.reflect.Constructor; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.function.Supplier; - -/** - * @author Vlad Mihalcea - */ -public class ReflectionUtil { - - /** - * Get a field from a given class - * @param clazz clazz - * @param name field name - * @return field object - */ - public static Field getField(Class clazz, String name) { - try { - Field field = clazz.getDeclaredField( name ); - field.setAccessible( true ); - return field; - } - catch ( NoSuchFieldException e ) { - throw new IllegalArgumentException( "Class " + clazz + " does not contain a " + name + " field", e); - } - } - - /** - * Get a field value from a given object - * @param target Object whose field is being read - * @param name field name - * @return field object - */ - public static T getFieldValue(Object target, String name) { - try { - Field field = target.getClass().getDeclaredField( name ); - field.setAccessible( true ); - return (T) field.get( target ); - } - catch ( NoSuchFieldException e ) { - throw new IllegalArgumentException( "Class " + target.getClass() + " does not contain a " + name + " field", e); - } - catch ( IllegalAccessException e ) { - throw new IllegalArgumentException( "Cannot set field " + name, e); - } - } - - /** - * Set target Object field to a certain value - * @param target Object whose field is being set - * @param field Object field to set - * @param value the new value for the given field - */ - public static void setField(Object target, Field field, Object value) { - try { - field.set( target, value ); - } - catch ( IllegalAccessException e ) { - throw new IllegalArgumentException("Field " + field + " could not be set", e ); - } - } - - /** - * Set target Object field to a certain value - * @param target Object whose field is being set - * @param fieldName Object field naem to set - * @param value the new value for the given field - */ - public static void setField(Object target, String fieldName, Object value) { - try { - Field field = getField(target.getClass(), fieldName); - field.set( target, value ); - } - catch ( IllegalAccessException e ) { - throw new IllegalArgumentException("Field " + fieldName + " could not be set", e ); - } - } - - /** - * New target Object instance using the given arguments - * @param constructorSupplier constructor supplier - * @param args Constructor arguments - * @return new Object instance - */ - public static T newInstance(Supplier> constructorSupplier, Object... args) { - try { - Constructor constructor = constructorSupplier.get(); - constructor.setAccessible( true ); - return (T) constructor.newInstance( args ); - } - catch ( IllegalAccessException | InstantiationException | InvocationTargetException e ) { - throw new IllegalArgumentException("Constructor could not be called", e ); - } - } - - /** - * New target Object instance using the given Class name - * @param className class name - * @return new Object instance - */ - public static T newInstance(String className) { - try { - return (T) Class.forName( className ).newInstance(); - } - catch ( ClassNotFoundException | IllegalAccessException | InstantiationException e ) { - throw new IllegalArgumentException("Constructor could not be called", e ); - } - } - - /** - * Get setter method - * - * @param target target object - * @param property property - * @param parameterType setter parameter type - * @return setter method - */ - public static Method getSetter(Object target, String property, Class parameterType) { - String setterMethodName = "set" + property.substring(0, 1).toUpperCase() + property.substring(1); - Method setter = getMethod(target, setterMethodName, parameterType); - setter.setAccessible(true); - return setter; - } - - /** - * Get target method - * - * @param target target object - * @param methodName method name - * @param parameterTypes method parameter types - * @return return value - */ - public static Method getMethod(Object target, String methodName, Class... parameterTypes) { - try { - return target.getClass().getMethod(methodName, parameterTypes); - } catch (NoSuchMethodException e) { - throw new IllegalArgumentException(e); - } - } - - /** - * Invoke setter method with the given parameter - * - * @param target target object - * @param property property - * @param parameter setter parameter - */ - public static void setProperty(Object target, String property, Object parameter) { - Method setter = getSetter( target, property, parameter.getClass()); - try { - setter.invoke(target, parameter); - } catch (IllegalAccessException | InvocationTargetException e) { - throw new IllegalArgumentException(e); - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/util/jdbc/SQLStatementInterceptor.java b/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/SQLStatementInterceptor.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/test/util/jdbc/SQLStatementInterceptor.java rename to hibernate-testing/src/main/java/org/hibernate/testing/jdbc/SQLStatementInterceptor.java index aba5718df6..bc37c11b97 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/util/jdbc/SQLStatementInterceptor.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/SQLStatementInterceptor.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.test.util.jdbc; +package org.hibernate.testing.jdbc; import java.util.LinkedList; diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/util/ReflectionUtil.java b/hibernate-testing/src/main/java/org/hibernate/testing/util/ReflectionUtil.java new file mode 100644 index 0000000000..c75fb8270f --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/util/ReflectionUtil.java @@ -0,0 +1,221 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.testing.util; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.function.Supplier; + +/** + * @author Vlad Mihalcea + */ +public class ReflectionUtil { + + /** + * Get a field from a given class + * + * @param clazz clazz + * @param name field name + * + * @return field object + */ + public static Field getField(Class clazz, String name) { + try { + Field field = clazz.getDeclaredField( name ); + field.setAccessible( true ); + return field; + } + catch (NoSuchFieldException e) { + Class superClass = clazz.getSuperclass(); + if ( !clazz.equals( superClass ) ) { + return getField( superClass, name ); + } + throw new IllegalArgumentException( "Class " + clazz + " does not contain a " + name + " field", e ); + } + } + + /** + * Get a field value from a given object + * + * @param target Object whose field is being read + * @param name field name + * + * @return field object + */ + public static T getFieldValue(Object target, String name) { + try { + Field field = target.getClass().getDeclaredField( name ); + field.setAccessible( true ); + return (T) field.get( target ); + } + catch (NoSuchFieldException e) { + throw new IllegalArgumentException( + "Class " + target.getClass() + " does not contain a " + name + " field", + e + ); + } + catch (IllegalAccessException e) { + throw new IllegalArgumentException( "Cannot set field " + name, e ); + } + } + + /** + * Get a field value from a given class + * + * @param target Class whose field is being read + * @param name field name + * + * @return field value + */ + public static T getStaticFieldValue(Class target, String name) { + try { + Field field = getField( target, name ); + return (T) field.get( null ); + } + catch (IllegalAccessException e) { + throw new IllegalArgumentException( "Cannot set field " + name, e ); + } + } + + /** + * Set target Object field to a certain value + * + * @param target Object whose field is being set + * @param field Object field to set + * @param value the new value for the given field + */ + public static void setField(Object target, Field field, Object value) { + try { + field.set( target, value ); + } + catch (IllegalAccessException e) { + throw new IllegalArgumentException( "Field " + field + " could not be set", e ); + } + } + + /** + * Set target Object field to a certain value + * + * @param target Object whose field is being set + * @param fieldName Object field naem to set + * @param value the new value for the given field + */ + public static void setField(Object target, String fieldName, Object value) { + try { + Field field = getField( target.getClass(), fieldName ); + field.set( target, value ); + } + catch (IllegalAccessException e) { + throw new IllegalArgumentException( "Field " + fieldName + " could not be set", e ); + } + } + + /** + * Set target Class field to a certain value + * + * @param target Class whose field is being set + * @param fieldName Class field name to set + * @param value the new value for the given field + */ + public static void setStaticField(Class target, String fieldName, Object value) { + try { + Field field = getField( target, fieldName ); + field.set( null, value ); + } + catch (IllegalAccessException e) { + throw new IllegalArgumentException( "Field " + fieldName + " could not be set", e ); + } + } + + /** + * New target Object instance using the given arguments + * + * @param constructorSupplier constructor supplier + * @param args Constructor arguments + * + * @return new Object instance + */ + public static T newInstance(Supplier> constructorSupplier, Object... args) { + try { + Constructor constructor = constructorSupplier.get(); + constructor.setAccessible( true ); + return (T) constructor.newInstance( args ); + } + catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { + throw new IllegalArgumentException( "Constructor could not be called", e ); + } + } + + /** + * New target Object instance using the given Class name + * + * @param className class name + * + * @return new Object instance + */ + public static T newInstance(String className) { + try { + return (T) Class.forName( className ).newInstance(); + } + catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) { + throw new IllegalArgumentException( "Constructor could not be called", e ); + } + } + + /** + * Get setter method + * + * @param target target object + * @param property property + * @param parameterType setter parameter type + * + * @return setter method + */ + public static Method getSetter(Object target, String property, Class parameterType) { + String setterMethodName = "set" + property.substring( 0, 1 ).toUpperCase() + property.substring( 1 ); + Method setter = getMethod( target, setterMethodName, parameterType ); + setter.setAccessible( true ); + return setter; + } + + /** + * Get target method + * + * @param target target object + * @param methodName method name + * @param parameterTypes method parameter types + * + * @return return value + */ + public static Method getMethod(Object target, String methodName, Class... parameterTypes) { + try { + return target.getClass().getMethod( methodName, parameterTypes ); + } + catch (NoSuchMethodException e) { + throw new IllegalArgumentException( e ); + } + } + + /** + * Invoke setter method with the given parameter + * + * @param target target object + * @param property property + * @param parameter setter parameter + */ + public static void setProperty(Object target, String property, Object parameter) { + Method setter = getSetter( target, property, parameter.getClass() ); + try { + setter.invoke( target, parameter ); + } + catch (IllegalAccessException | InvocationTargetException e) { + throw new IllegalArgumentException( e ); + } + } +}