JdbcUtils uses JDBC 4.1 getObject(int, Class) for unknown ResultSet value types
Comes with general JDBC 3.0+ baseline upgrade, removing defensive measures. Issue: SPR-11600
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -30,7 +30,6 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.jdbc.support.nativejdbc.NativeJdbcExtractor;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
@@ -228,18 +227,11 @@ public class PreparedStatementCreatorFactory {
|
||||
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
|
||||
PreparedStatement ps;
|
||||
if (generatedKeysColumnNames != null || returnGeneratedKeys) {
|
||||
try {
|
||||
if (generatedKeysColumnNames != null) {
|
||||
ps = con.prepareStatement(this.actualSql, generatedKeysColumnNames);
|
||||
}
|
||||
else {
|
||||
ps = con.prepareStatement(this.actualSql, PreparedStatement.RETURN_GENERATED_KEYS);
|
||||
}
|
||||
if (generatedKeysColumnNames != null) {
|
||||
ps = con.prepareStatement(this.actualSql, generatedKeysColumnNames);
|
||||
}
|
||||
catch (AbstractMethodError err) {
|
||||
throw new InvalidDataAccessResourceUsageException(
|
||||
"Your JDBC driver is not compliant with JDBC 3.0 - " +
|
||||
"it does not support retrieval of auto-generated keys", err);
|
||||
else {
|
||||
ps = con.prepareStatement(this.actualSql, PreparedStatement.RETURN_GENERATED_KEYS);
|
||||
}
|
||||
}
|
||||
else if (resultSetType == ResultSet.TYPE_FORWARD_ONLY && !updatableResults) {
|
||||
|
||||
@@ -87,10 +87,8 @@ public abstract class StatementCreatorUtils {
|
||||
private static final Map<Class<?>, Integer> javaTypeToSqlTypeMap = new HashMap<Class<?>, Integer>(32);
|
||||
|
||||
static {
|
||||
/* JDBC 3.0 only - not compatible with e.g. MySQL at present
|
||||
javaTypeToSqlTypeMap.put(boolean.class, new Integer(Types.BOOLEAN));
|
||||
javaTypeToSqlTypeMap.put(Boolean.class, new Integer(Types.BOOLEAN));
|
||||
*/
|
||||
javaTypeToSqlTypeMap.put(boolean.class, Types.BOOLEAN);
|
||||
javaTypeToSqlTypeMap.put(Boolean.class, Types.BOOLEAN);
|
||||
javaTypeToSqlTypeMap.put(byte.class, Types.TINYINT);
|
||||
javaTypeToSqlTypeMap.put(Byte.class, Types.TINYINT);
|
||||
javaTypeToSqlTypeMap.put(short.class, Types.SMALLINT);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.jdbc.datasource;
|
||||
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Savepoint;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -41,9 +42,6 @@ import org.springframework.transaction.support.SmartTransactionObject;
|
||||
* will automatically delegate to this, as it autodetects transaction
|
||||
* objects that implement the SavepointManager interface.
|
||||
*
|
||||
* <p>Note that savepoints are only supported for drivers which
|
||||
* support JDBC 3.0 or higher.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 1.1
|
||||
*/
|
||||
@@ -109,15 +107,9 @@ public abstract class JdbcTransactionObjectSupport implements SavepointManager,
|
||||
throw new NestedTransactionNotSupportedException(
|
||||
"Cannot create a nested transaction because savepoints are not supported by your JDBC driver");
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
throw new NestedTransactionNotSupportedException(
|
||||
"Cannot create a nested transaction because your JDBC driver is not a JDBC 3.0 driver", ex);
|
||||
}
|
||||
try {
|
||||
return conHolder.createSavepoint();
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
catch (SQLException ex) {
|
||||
throw new CannotCreateTransactionException("Could not create JDBC savepoint", ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -26,9 +26,9 @@ import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.ResultSetMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLFeatureNotSupportedException;
|
||||
import java.sql.Statement;
|
||||
import java.sql.Types;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -36,6 +36,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.jdbc.CannotGetJdbcConnectionException;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
/**
|
||||
* Generic utility methods for working with JDBC. Mainly for internal use
|
||||
@@ -53,6 +54,10 @@ public abstract class JdbcUtils {
|
||||
public static final int TYPE_UNKNOWN = Integer.MIN_VALUE;
|
||||
|
||||
|
||||
// Check for JDBC 4.1 getObject(int, Class) method - available on JDK 7 and higher
|
||||
private static final boolean getObjectWithTypeAvailable =
|
||||
ClassUtils.hasMethod(ResultSet.class, "getObject", int.class, Class.class);
|
||||
|
||||
private static final Log logger = LogFactory.getLog(JdbcUtils.class);
|
||||
|
||||
|
||||
@@ -134,74 +139,74 @@ public abstract class JdbcUtils {
|
||||
return getResultSetValue(rs, index);
|
||||
}
|
||||
|
||||
Object value = null;
|
||||
boolean wasNullCheck = false;
|
||||
Object value;
|
||||
|
||||
// Explicitly extract typed value, as far as possible.
|
||||
if (String.class.equals(requiredType)) {
|
||||
value = rs.getString(index);
|
||||
return rs.getString(index);
|
||||
}
|
||||
else if (boolean.class.equals(requiredType) || Boolean.class.equals(requiredType)) {
|
||||
value = rs.getBoolean(index);
|
||||
wasNullCheck = true;
|
||||
}
|
||||
else if (byte.class.equals(requiredType) || Byte.class.equals(requiredType)) {
|
||||
value = rs.getByte(index);
|
||||
wasNullCheck = true;
|
||||
}
|
||||
else if (short.class.equals(requiredType) || Short.class.equals(requiredType)) {
|
||||
value = rs.getShort(index);
|
||||
wasNullCheck = true;
|
||||
}
|
||||
else if (int.class.equals(requiredType) || Integer.class.equals(requiredType)) {
|
||||
value = rs.getInt(index);
|
||||
wasNullCheck = true;
|
||||
}
|
||||
else if (long.class.equals(requiredType) || Long.class.equals(requiredType)) {
|
||||
value = rs.getLong(index);
|
||||
wasNullCheck = true;
|
||||
}
|
||||
else if (float.class.equals(requiredType) || Float.class.equals(requiredType)) {
|
||||
value = rs.getFloat(index);
|
||||
wasNullCheck = true;
|
||||
}
|
||||
else if (double.class.equals(requiredType) || Double.class.equals(requiredType) ||
|
||||
Number.class.equals(requiredType)) {
|
||||
value = rs.getDouble(index);
|
||||
wasNullCheck = true;
|
||||
}
|
||||
else if (byte[].class.equals(requiredType)) {
|
||||
value = rs.getBytes(index);
|
||||
}
|
||||
else if (java.sql.Date.class.equals(requiredType)) {
|
||||
value = rs.getDate(index);
|
||||
}
|
||||
else if (java.sql.Time.class.equals(requiredType)) {
|
||||
value = rs.getTime(index);
|
||||
}
|
||||
else if (java.sql.Timestamp.class.equals(requiredType) || java.util.Date.class.equals(requiredType)) {
|
||||
value = rs.getTimestamp(index);
|
||||
}
|
||||
else if (BigDecimal.class.equals(requiredType)) {
|
||||
value = rs.getBigDecimal(index);
|
||||
return rs.getBigDecimal(index);
|
||||
}
|
||||
else if (java.sql.Date.class.equals(requiredType)) {
|
||||
return rs.getDate(index);
|
||||
}
|
||||
else if (java.sql.Time.class.equals(requiredType)) {
|
||||
return rs.getTime(index);
|
||||
}
|
||||
else if (java.sql.Timestamp.class.equals(requiredType) || java.util.Date.class.equals(requiredType)) {
|
||||
return rs.getTimestamp(index);
|
||||
}
|
||||
else if (byte[].class.equals(requiredType)) {
|
||||
return rs.getBytes(index);
|
||||
}
|
||||
else if (Blob.class.equals(requiredType)) {
|
||||
value = rs.getBlob(index);
|
||||
return rs.getBlob(index);
|
||||
}
|
||||
else if (Clob.class.equals(requiredType)) {
|
||||
value = rs.getClob(index);
|
||||
return rs.getClob(index);
|
||||
}
|
||||
else {
|
||||
// Some unknown type desired -> rely on getObject.
|
||||
value = getResultSetValue(rs, index);
|
||||
if (getObjectWithTypeAvailable) {
|
||||
try {
|
||||
return rs.getObject(index, requiredType);
|
||||
}
|
||||
catch (SQLFeatureNotSupportedException ex) {
|
||||
logger.debug("JDBC driver does not support JDBC 4.1 'getObject(int, Class)' method", ex);
|
||||
}
|
||||
catch (AbstractMethodError err) {
|
||||
logger.debug("JDBC driver does not implement JDBC 4.1 'getObject(int, Class)' method", err);
|
||||
}
|
||||
}
|
||||
// Fall back to getObject without type specification...
|
||||
return getResultSetValue(rs, index);
|
||||
}
|
||||
|
||||
// Perform was-null check if demanded (for results that the
|
||||
// JDBC driver returns as primitives).
|
||||
if (wasNullCheck && value != null && rs.wasNull()) {
|
||||
value = null;
|
||||
}
|
||||
return value;
|
||||
// Perform was-null check if necessary (for results that the JDBC driver returns as primitives).
|
||||
return (rs.wasNull() ? null : value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -234,15 +239,12 @@ public abstract class JdbcUtils {
|
||||
else if (obj instanceof Clob) {
|
||||
obj = rs.getString(index);
|
||||
}
|
||||
else if (className != null &&
|
||||
("oracle.sql.TIMESTAMP".equals(className) ||
|
||||
"oracle.sql.TIMESTAMPTZ".equals(className))) {
|
||||
else if ("oracle.sql.TIMESTAMP".equals(className) || "oracle.sql.TIMESTAMPTZ".equals(className)) {
|
||||
obj = rs.getTimestamp(index);
|
||||
}
|
||||
else if (className != null && className.startsWith("oracle.sql.DATE")) {
|
||||
String metaDataClassName = rs.getMetaData().getColumnClassName(index);
|
||||
if ("java.sql.Timestamp".equals(metaDataClassName) ||
|
||||
"oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
|
||||
if ("java.sql.Timestamp".equals(metaDataClassName) || "oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
|
||||
obj = rs.getTimestamp(index);
|
||||
}
|
||||
else {
|
||||
@@ -371,9 +373,6 @@ public abstract class JdbcUtils {
|
||||
catch (SQLException ex) {
|
||||
logger.debug("JDBC driver 'supportsBatchUpdates' method threw exception", ex);
|
||||
}
|
||||
catch (AbstractMethodError err) {
|
||||
logger.debug("JDBC driver does not support JDBC 2.0 'supportsBatchUpdates' method", err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user