The fix implemented for issue
HHH-8022
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:
public ResultSet extract(PreparedStatement statement) {
if (isTypeOf(statement, CallableStatement.class)) {
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 {
matches = statement.isWrapperFor(type);
} catch (SQLException e) {
matches = type.isAssignableFrom(statement.getClass());
}
return matches;
}
|