We're updating the issue view to help you get more done. 

Compatibility improvement suggestion for org.hibernate.engine.jdbc.internal.ResultSetReturnImpl

Description

The fix implemented for issue in org.hibernate.engine.jdbc.internal.ResultSetReturnImpl performs an instanceof check on the statement object to determine if the current statement is an instance of CallableStatement. This presents a potential problem if a framework wraps a statement object in either a proxy or a concrete class that implements both PreparedStatement and CallableStatement.

This can result in wrapped/proxied PreparedStatement objects being incorrectly identified as CallableStatement instances with the end result often being a ClassCastException, AbstractMethodError, or NoSuchMethodException error in the wrapper or proxy.

Since JDK 6 is now a minimum requirement it seems like a more compatible fix would have been to call java.sql.Wrapper.isWrapperFor(CallableStatement.class) method on the statement object to determine the instance type instead of using the instanceof keyword. While I'm not stating that the implemented fix is technically wrong, I believe the use of Wrapper.isWrapperFor would promote improved compatibility across the greatest range of pooling frameworks, JDBC drivers, etc.

Improvement Suggestion:

org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.java

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 public ResultSet extract(PreparedStatement statement) { // IMPL NOTE : SQL logged by caller if (isTypeOf(statement, CallableStatement.class)) { // We actually need to extract from Callable statement. Although // this seems needless, Oracle can return an // OracleCallableStatementWrapper that finds its way to this method, // rather than extract(CallableStatement). See HHH-8022. final CallableStatement callableStatement = (CallableStatement) statement; return extract( callableStatement ); } try { final ResultSet rs; try { jdbcCoordinator.getTransactionCoordinator().getTransactionContext().startStatementExecution(); rs = statement.executeQuery(); } finally { jdbcCoordinator.getTransactionCoordinator().getTransactionContext().endStatementExecution(); } postExtract( rs, statement ); return rs; } catch (SQLException e) { throw sqlExceptionHelper.convert( e, "could not extract ResultSet" ); } } private boolean isTypeOf(final Statement statement, final Class<? extends Statement> type) { boolean matches; try { // Verify if the statement either implements the interface directly // or is a wrapper for the specified type via the JDBC API matches = statement.isWrapperFor(type); } catch (SQLException e) { // If the wrapper check fails for some reason, fall back to assignable class verification matches = type.isAssignableFrom(statement.getClass()); } return matches; }

Environment

Hibernate Core 4.3.5, Oracle 11g

Status

Assignee

Brett Meyer

Reporter

Joel Bagley

Fix versions

Labels

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

backportDecision

None

Components

Affects versions

4.3.5
4.2.0.Final

Priority

Minor