Consistent use of @Nullable across the codebase (even for internals)
Beyond just formally declaring the current behavior, this revision actually enforces non-null behavior in selected signatures now, not tolerating null values anymore when not explicitly documented. It also changes some utility methods with historic null-in/null-out tolerance towards enforced non-null return values, making them a proper citizen in non-null assignments. Some issues are left as to-do: in particular a thorough revision of spring-test, and a few tests with unclear failures (ignored as "TODO: NULLABLE") to be sorted out in a follow-up commit. Issue: SPR-15540
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,7 @@ package org.springframework.jdbc;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Fatal exception thrown when we can't connect to an RDBMS using JDBC.
|
||||
@@ -33,7 +34,7 @@ public class CannotGetJdbcConnectionException extends DataAccessResourceFailureE
|
||||
* @param msg the detail message
|
||||
* @param ex SQLException root cause
|
||||
*/
|
||||
public CannotGetJdbcConnectionException(String msg, SQLException ex) {
|
||||
public CannotGetJdbcConnectionException(String msg, @Nullable SQLException ex) {
|
||||
super(msg, ex);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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,8 @@
|
||||
|
||||
package org.springframework.jdbc.config;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
@@ -23,11 +25,8 @@ import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that
|
||||
* parses an {@code embedded-database} element and creates a {@link BeanDefinition}
|
||||
@@ -56,7 +55,7 @@ class EmbeddedDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser
|
||||
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(@Nullable Element element, @Nullable ParserContext parserContext) {
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(EmbeddedDatabaseFactoryBean.class);
|
||||
setGenerateUniqueDatabaseNameFlag(element, builder);
|
||||
setDatabaseName(element, builder);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2011 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -25,7 +25,6 @@ import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
|
||||
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses an {@code initialize-database}
|
||||
@@ -39,7 +38,7 @@ import org.springframework.lang.Nullable;
|
||||
class InitializeDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(@Nullable Element element, @Nullable ParserContext parserContext) {
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DataSourceInitializer.class);
|
||||
builder.addPropertyReference("dataSource", element.getAttribute("data-source"));
|
||||
builder.addPropertyValue("enabled", element.getAttribute("enabled"));
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.jdbc.core;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Simple adapter for {@link PreparedStatementSetter} that applies a given array of arguments.
|
||||
*
|
||||
@@ -34,7 +36,7 @@ public class ArgumentPreparedStatementSetter implements PreparedStatementSetter,
|
||||
* Create a new ArgPreparedStatementSetter for the given arguments.
|
||||
* @param args the arguments to set
|
||||
*/
|
||||
public ArgumentPreparedStatementSetter(Object[] args) {
|
||||
public ArgumentPreparedStatementSetter(@Nullable Object[] args) {
|
||||
this.args = args;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -22,6 +22,7 @@ import java.sql.Types;
|
||||
import java.util.Collection;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Simple adapter for {@link PreparedStatementSetter} that applies
|
||||
@@ -42,7 +43,7 @@ public class ArgumentTypePreparedStatementSetter implements PreparedStatementSet
|
||||
* @param args the arguments to set
|
||||
* @param argTypes the corresponding SQL types of the arguments
|
||||
*/
|
||||
public ArgumentTypePreparedStatementSetter(Object[] args, int[] argTypes) {
|
||||
public ArgumentTypePreparedStatementSetter(@Nullable Object[] args, @Nullable int[] argTypes) {
|
||||
if ((args != null && argTypes == null) || (args == null && argTypes != null) ||
|
||||
(args != null && args.length != argTypes.length)) {
|
||||
throw new InvalidDataAccessApiUsageException("args and argTypes parameters must match");
|
||||
@@ -55,7 +56,7 @@ public class ArgumentTypePreparedStatementSetter implements PreparedStatementSet
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps) throws SQLException {
|
||||
int parameterPosition = 1;
|
||||
if (this.args != null) {
|
||||
if (this.args != null && this.argTypes != null) {
|
||||
for (int i = 0; i < this.args.length; i++) {
|
||||
Object arg = this.args[i];
|
||||
if (arg instanceof Collection && this.argTypes[i] != Types.ARRAY) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,25 +20,28 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Generic utility methods for working with JDBC batch statements. Mainly for internal use
|
||||
* within the framework.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 3.0
|
||||
*/
|
||||
public abstract class BatchUpdateUtils {
|
||||
|
||||
public static int[] executeBatchUpdate(String sql, final List<Object[]> batchValues, final int[] columnTypes, JdbcOperations jdbcOperations) {
|
||||
public static int[] executeBatchUpdate(
|
||||
String sql, final List<Object[]> batchValues, final int[] columnTypes, JdbcOperations jdbcOperations) {
|
||||
|
||||
return jdbcOperations.batchUpdate(
|
||||
sql,
|
||||
new BatchPreparedStatementSetter() {
|
||||
|
||||
@Override
|
||||
public void setValues(PreparedStatement ps, int i) throws SQLException {
|
||||
Object[] values = batchValues.get(i);
|
||||
setStatementParameters(values, ps, columnTypes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return batchValues.size();
|
||||
@@ -46,7 +49,9 @@ public abstract class BatchUpdateUtils {
|
||||
});
|
||||
}
|
||||
|
||||
protected static void setStatementParameters(Object[] values, PreparedStatement ps, int[] columnTypes) throws SQLException {
|
||||
protected static void setStatementParameters(Object[] values, PreparedStatement ps, @Nullable int[] columnTypes)
|
||||
throws SQLException {
|
||||
|
||||
int colIndex = 0;
|
||||
for (Object value : values) {
|
||||
colIndex++;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -363,12 +363,12 @@ public class BeanPropertyRowMapper<T> implements RowMapper<T> {
|
||||
* @param rs is the ResultSet holding the data
|
||||
* @param index is the column index
|
||||
* @param pd the bean property that each result object is expected to match
|
||||
* (or {@code null} if none specified)
|
||||
* @return the Object value
|
||||
* @throws SQLException in case of extraction failure
|
||||
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)
|
||||
*/
|
||||
protected Object getColumnValue(ResultSet rs, int index, @Nullable PropertyDescriptor pd) throws SQLException {
|
||||
@Nullable
|
||||
protected Object getColumnValue(ResultSet rs, int index, PropertyDescriptor pd) throws SQLException {
|
||||
return JdbcUtils.getResultSetValue(rs, index, pd.getPropertyType());
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -22,6 +22,7 @@ import java.sql.SQLException;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.LinkedCaseInsensitiveMap;
|
||||
|
||||
/**
|
||||
@@ -92,6 +93,7 @@ public class ColumnMapRowMapper implements RowMapper<Map<String, Object>> {
|
||||
* @return the Object returned
|
||||
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue
|
||||
*/
|
||||
@Nullable
|
||||
protected Object getColumnValue(ResultSet rs, int index) throws SQLException {
|
||||
return JdbcUtils.getResultSetValue(rs, index);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -102,6 +102,7 @@ public interface JdbcOperations {
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
* @see #query(String, Object[], ResultSetExtractor)
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -277,6 +278,7 @@ public interface JdbcOperations {
|
||||
* @return a result object returned by the action, or {@code null}
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
@Nullable
|
||||
<T> T execute(PreparedStatementCreator psc, PreparedStatementCallback<T> action) throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -306,6 +308,7 @@ public interface JdbcOperations {
|
||||
* @throws DataAccessException if there is any problem
|
||||
* @see PreparedStatementCreatorFactory
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(PreparedStatementCreator psc, ResultSetExtractor<T> rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -320,6 +323,7 @@ public interface JdbcOperations {
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, @Nullable PreparedStatementSetter pss, ResultSetExtractor<T> rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -335,6 +339,7 @@ public interface JdbcOperations {
|
||||
* @throws DataAccessException if the query fails
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, Object[] args, int[] argTypes, ResultSetExtractor<T> rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -350,6 +355,7 @@ public interface JdbcOperations {
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, Object[] args, ResultSetExtractor<T> rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
@@ -365,6 +371,7 @@ public interface JdbcOperations {
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, ResultSetExtractor<T> rse, @Nullable Object... args) throws DataAccessException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,7 +35,6 @@ import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -320,7 +319,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
|
||||
Assert.notNull(action, "Callback object must not be null");
|
||||
|
||||
Connection con = DataSourceUtils.getConnection(getDataSource());
|
||||
Connection con = DataSourceUtils.getConnection(obtainDataSource());
|
||||
try {
|
||||
// Create close-suppressing Connection proxy, also preparing returned Statements.
|
||||
Connection conToUse = createConnectionProxy(con);
|
||||
@@ -365,7 +364,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
|
||||
Assert.notNull(action, "Callback object must not be null");
|
||||
|
||||
Connection con = DataSourceUtils.getConnection(getDataSource());
|
||||
Connection con = DataSourceUtils.getConnection(obtainDataSource());
|
||||
Statement stmt = null;
|
||||
try {
|
||||
stmt = con.createStatement();
|
||||
@@ -442,7 +441,9 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
|
||||
@Override
|
||||
public <T> List<T> query(String sql, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(sql, new RowMapperResultSetExtractor<>(rowMapper));
|
||||
List<T> result = query(sql, new RowMapperResultSetExtractor<>(rowMapper));
|
||||
Assert.state(result != null, "No result list");
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -473,7 +474,9 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
|
||||
@Override
|
||||
public SqlRowSet queryForRowSet(String sql) throws DataAccessException {
|
||||
return query(sql, new SqlRowSetResultSetExtractor());
|
||||
SqlRowSet result = query(sql, new SqlRowSetResultSetExtractor());
|
||||
Assert.state(result != null, "No SqlRowSet");
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -482,7 +485,9 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing SQL update [" + sql + "]");
|
||||
}
|
||||
|
||||
class UpdateStatementCallback implements StatementCallback<Integer>, SqlProvider {
|
||||
|
||||
@Override
|
||||
public Integer doInStatement(Statement stmt) throws SQLException {
|
||||
int rows = stmt.executeUpdate(sql);
|
||||
@@ -491,12 +496,14 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSql() {
|
||||
return sql;
|
||||
}
|
||||
}
|
||||
return execute(new UpdateStatementCallback());
|
||||
|
||||
return updateCount(execute(new UpdateStatementCallback()));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -548,7 +555,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
return rowsAffected;
|
||||
}
|
||||
|
||||
private String appendSql(String sql, String statement) {
|
||||
private String appendSql(@Nullable String sql, String statement) {
|
||||
return (StringUtils.isEmpty(sql) ? statement : sql + "; " + statement);
|
||||
}
|
||||
|
||||
@@ -558,7 +565,9 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
}
|
||||
}
|
||||
|
||||
return execute(new BatchUpdateStatementCallback());
|
||||
int[] result = execute(new BatchUpdateStatementCallback());
|
||||
Assert.state(result != null, "No update counts");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -577,7 +586,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
logger.debug("Executing prepared SQL statement" + (sql != null ? " [" + sql + "]" : ""));
|
||||
}
|
||||
|
||||
Connection con = DataSourceUtils.getConnection(getDataSource());
|
||||
Connection con = DataSourceUtils.getConnection(obtainDataSource());
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = psc.createPreparedStatement(con);
|
||||
@@ -593,7 +602,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
((ParameterDisposer) psc).cleanupParameters();
|
||||
}
|
||||
String sql = getSql(psc);
|
||||
psc = null;
|
||||
JdbcUtils.closeStatement(ps);
|
||||
ps = null;
|
||||
DataSourceUtils.releaseConnection(con, getDataSource());
|
||||
@@ -626,6 +634,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if there is any problem
|
||||
*/
|
||||
@Nullable
|
||||
public <T> T query(
|
||||
PreparedStatementCreator psc, @Nullable final PreparedStatementSetter pss, final ResultSetExtractor<T> rse)
|
||||
throws DataAccessException {
|
||||
@@ -670,7 +679,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T query(String sql, Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {
|
||||
public <T> T query(String sql, @Nullable Object[] args, ResultSetExtractor<T> rse) throws DataAccessException {
|
||||
return query(sql, newArgPreparedStatementSetter(args), rse);
|
||||
}
|
||||
|
||||
@@ -706,27 +715,27 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
|
||||
@Override
|
||||
public <T> List<T> query(PreparedStatementCreator psc, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(psc, new RowMapperResultSetExtractor<>(rowMapper));
|
||||
return nonNull(query(psc, new RowMapperResultSetExtractor<>(rowMapper)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> query(String sql, @Nullable PreparedStatementSetter pss, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(sql, pss, new RowMapperResultSetExtractor<>(rowMapper));
|
||||
return nonNull(query(sql, pss, new RowMapperResultSetExtractor<>(rowMapper)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> query(String sql, Object[] args, int[] argTypes, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(sql, args, argTypes, new RowMapperResultSetExtractor<>(rowMapper));
|
||||
return nonNull(query(sql, args, argTypes, new RowMapperResultSetExtractor<>(rowMapper)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return query(sql, args, new RowMapperResultSetExtractor<>(rowMapper));
|
||||
public <T> List<T> query(String sql, @Nullable Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
return nonNull(query(sql, args, new RowMapperResultSetExtractor<>(rowMapper)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<T> query(String sql, RowMapper<T> rowMapper, @Nullable Object... args) throws DataAccessException {
|
||||
return query(sql, args, new RowMapperResultSetExtractor<>(rowMapper));
|
||||
return nonNull(query(sql, args, new RowMapperResultSetExtractor<>(rowMapper)));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -738,7 +747,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T queryForObject(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
public <T> T queryForObject(String sql, @Nullable Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
List<T> results = query(sql, args, new RowMapperResultSetExtractor<>(rowMapper, 1));
|
||||
return DataAccessUtils.requiredSingleResult(results);
|
||||
}
|
||||
@@ -803,38 +812,36 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
|
||||
@Override
|
||||
public SqlRowSet queryForRowSet(String sql, Object[] args, int[] argTypes) throws DataAccessException {
|
||||
return query(sql, args, argTypes, new SqlRowSetResultSetExtractor());
|
||||
return nonNull(query(sql, args, argTypes, new SqlRowSetResultSetExtractor()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlRowSet queryForRowSet(String sql, @Nullable Object... args) throws DataAccessException {
|
||||
return query(sql, args, new SqlRowSetResultSetExtractor());
|
||||
return nonNull(query(sql, args, new SqlRowSetResultSetExtractor()));
|
||||
}
|
||||
|
||||
protected int update(final PreparedStatementCreator psc, final PreparedStatementSetter pss)
|
||||
protected int update(final PreparedStatementCreator psc, @Nullable final PreparedStatementSetter pss)
|
||||
throws DataAccessException {
|
||||
|
||||
logger.debug("Executing prepared SQL update");
|
||||
return execute(psc, new PreparedStatementCallback<Integer>() {
|
||||
@Override
|
||||
public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException {
|
||||
try {
|
||||
if (pss != null) {
|
||||
pss.setValues(ps);
|
||||
}
|
||||
int rows = ps.executeUpdate();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SQL update affected " + rows + " rows");
|
||||
}
|
||||
return rows;
|
||||
|
||||
return updateCount(execute(psc, ps -> {
|
||||
try {
|
||||
if (pss != null) {
|
||||
pss.setValues(ps);
|
||||
}
|
||||
finally {
|
||||
if (pss instanceof ParameterDisposer) {
|
||||
((ParameterDisposer) pss).cleanupParameters();
|
||||
}
|
||||
int rows = ps.executeUpdate();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SQL update affected " + rows + " rows");
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
finally {
|
||||
if (pss instanceof ParameterDisposer) {
|
||||
((ParameterDisposer) pss).cleanupParameters();
|
||||
}
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -849,29 +856,26 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
Assert.notNull(generatedKeyHolder, "KeyHolder must not be null");
|
||||
logger.debug("Executing SQL update and returning generated keys");
|
||||
|
||||
return execute(psc, new PreparedStatementCallback<Integer>() {
|
||||
@Override
|
||||
public Integer doInPreparedStatement(PreparedStatement ps) throws SQLException {
|
||||
int rows = ps.executeUpdate();
|
||||
List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
|
||||
generatedKeys.clear();
|
||||
ResultSet keys = ps.getGeneratedKeys();
|
||||
if (keys != null) {
|
||||
try {
|
||||
RowMapperResultSetExtractor<Map<String, Object>> rse =
|
||||
new RowMapperResultSetExtractor<>(getColumnMapRowMapper(), 1);
|
||||
generatedKeys.addAll(rse.extractData(keys));
|
||||
}
|
||||
finally {
|
||||
JdbcUtils.closeResultSet(keys);
|
||||
}
|
||||
return updateCount(execute(psc, ps -> {
|
||||
int rows = ps.executeUpdate();
|
||||
List<Map<String, Object>> generatedKeys = generatedKeyHolder.getKeyList();
|
||||
generatedKeys.clear();
|
||||
ResultSet keys = ps.getGeneratedKeys();
|
||||
if (keys != null) {
|
||||
try {
|
||||
RowMapperResultSetExtractor<Map<String, Object>> rse =
|
||||
new RowMapperResultSetExtractor<>(getColumnMapRowMapper(), 1);
|
||||
generatedKeys.addAll(nonNull(rse.extractData(keys)));
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SQL update affected " + rows + " rows and returned " + generatedKeys.size() + " keys");
|
||||
finally {
|
||||
JdbcUtils.closeResultSet(keys);
|
||||
}
|
||||
return rows;
|
||||
}
|
||||
});
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("SQL update affected " + rows + " rows and returned " + generatedKeys.size() + " keys");
|
||||
}
|
||||
return rows;
|
||||
}));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -895,47 +899,47 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
logger.debug("Executing SQL batch update [" + sql + "]");
|
||||
}
|
||||
|
||||
return execute(sql, new PreparedStatementCallback<int[]>() {
|
||||
@Override
|
||||
public int[] doInPreparedStatement(PreparedStatement ps) throws SQLException {
|
||||
try {
|
||||
int batchSize = pss.getBatchSize();
|
||||
InterruptibleBatchPreparedStatementSetter ipss =
|
||||
(pss instanceof InterruptibleBatchPreparedStatementSetter ?
|
||||
(InterruptibleBatchPreparedStatementSetter) pss : null);
|
||||
if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
|
||||
for (int i = 0; i < batchSize; i++) {
|
||||
pss.setValues(ps, i);
|
||||
if (ipss != null && ipss.isBatchExhausted(i)) {
|
||||
break;
|
||||
}
|
||||
ps.addBatch();
|
||||
int[] result = execute(sql, (PreparedStatementCallback<int[]>) ps -> {
|
||||
try {
|
||||
int batchSize = pss.getBatchSize();
|
||||
InterruptibleBatchPreparedStatementSetter ipss =
|
||||
(pss instanceof InterruptibleBatchPreparedStatementSetter ?
|
||||
(InterruptibleBatchPreparedStatementSetter) pss : null);
|
||||
if (JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
|
||||
for (int i = 0; i < batchSize; i++) {
|
||||
pss.setValues(ps, i);
|
||||
if (ipss != null && ipss.isBatchExhausted(i)) {
|
||||
break;
|
||||
}
|
||||
return ps.executeBatch();
|
||||
}
|
||||
else {
|
||||
List<Integer> rowsAffected = new ArrayList<>();
|
||||
for (int i = 0; i < batchSize; i++) {
|
||||
pss.setValues(ps, i);
|
||||
if (ipss != null && ipss.isBatchExhausted(i)) {
|
||||
break;
|
||||
}
|
||||
rowsAffected.add(ps.executeUpdate());
|
||||
}
|
||||
int[] rowsAffectedArray = new int[rowsAffected.size()];
|
||||
for (int i = 0; i < rowsAffectedArray.length; i++) {
|
||||
rowsAffectedArray[i] = rowsAffected.get(i);
|
||||
}
|
||||
return rowsAffectedArray;
|
||||
ps.addBatch();
|
||||
}
|
||||
return ps.executeBatch();
|
||||
}
|
||||
finally {
|
||||
if (pss instanceof ParameterDisposer) {
|
||||
((ParameterDisposer) pss).cleanupParameters();
|
||||
else {
|
||||
List<Integer> rowsAffected = new ArrayList<>();
|
||||
for (int i = 0; i < batchSize; i++) {
|
||||
pss.setValues(ps, i);
|
||||
if (ipss != null && ipss.isBatchExhausted(i)) {
|
||||
break;
|
||||
}
|
||||
rowsAffected.add(ps.executeUpdate());
|
||||
}
|
||||
int[] rowsAffectedArray = new int[rowsAffected.size()];
|
||||
for (int i = 0; i < rowsAffectedArray.length; i++) {
|
||||
rowsAffectedArray[i] = rowsAffected.get(i);
|
||||
}
|
||||
return rowsAffectedArray;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (pss instanceof ParameterDisposer) {
|
||||
((ParameterDisposer) pss).cleanupParameters();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Assert.state(result != null, "No result array");
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -955,49 +959,49 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Executing SQL batch update [" + sql + "] with a batch size of " + batchSize);
|
||||
}
|
||||
return execute(sql, new PreparedStatementCallback<int[][]>() {
|
||||
@Override
|
||||
public int[][] doInPreparedStatement(PreparedStatement ps) throws SQLException {
|
||||
List<int[]> rowsAffected = new ArrayList<>();
|
||||
try {
|
||||
boolean batchSupported = true;
|
||||
if (!JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
|
||||
batchSupported = false;
|
||||
logger.warn("JDBC Driver does not support Batch updates; resorting to single statement execution");
|
||||
}
|
||||
int n = 0;
|
||||
for (T obj : batchArgs) {
|
||||
pss.setValues(ps, obj);
|
||||
n++;
|
||||
if (batchSupported) {
|
||||
ps.addBatch();
|
||||
if (n % batchSize == 0 || n == batchArgs.size()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
int batchIdx = (n % batchSize == 0) ? n / batchSize : (n / batchSize) + 1;
|
||||
int items = n - ((n % batchSize == 0) ? n / batchSize - 1 : (n / batchSize)) * batchSize;
|
||||
logger.debug("Sending SQL batch update #" + batchIdx + " with " + items + " items");
|
||||
}
|
||||
rowsAffected.add(ps.executeBatch());
|
||||
}
|
||||
}
|
||||
else {
|
||||
int i = ps.executeUpdate();
|
||||
rowsAffected.add(new int[] {i});
|
||||
}
|
||||
}
|
||||
int[][] result = new int[rowsAffected.size()][];
|
||||
for (int i = 0; i < result.length; i++) {
|
||||
result[i] = rowsAffected.get(i);
|
||||
}
|
||||
return result;
|
||||
int[][] result = execute(sql, (PreparedStatementCallback<int[][]>) ps -> {
|
||||
List<int[]> rowsAffected = new ArrayList<>();
|
||||
try {
|
||||
boolean batchSupported = true;
|
||||
if (!JdbcUtils.supportsBatchUpdates(ps.getConnection())) {
|
||||
batchSupported = false;
|
||||
logger.warn("JDBC Driver does not support Batch updates; resorting to single statement execution");
|
||||
}
|
||||
finally {
|
||||
if (pss instanceof ParameterDisposer) {
|
||||
((ParameterDisposer) pss).cleanupParameters();
|
||||
int n = 0;
|
||||
for (T obj : batchArgs) {
|
||||
pss.setValues(ps, obj);
|
||||
n++;
|
||||
if (batchSupported) {
|
||||
ps.addBatch();
|
||||
if (n % batchSize == 0 || n == batchArgs.size()) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
int batchIdx = (n % batchSize == 0) ? n / batchSize : (n / batchSize) + 1;
|
||||
int items = n - ((n % batchSize == 0) ? n / batchSize - 1 : (n / batchSize)) * batchSize;
|
||||
logger.debug("Sending SQL batch update #" + batchIdx + " with " + items + " items");
|
||||
}
|
||||
rowsAffected.add(ps.executeBatch());
|
||||
}
|
||||
}
|
||||
else {
|
||||
int i = ps.executeUpdate();
|
||||
rowsAffected.add(new int[] {i});
|
||||
}
|
||||
}
|
||||
int[][] result1 = new int[rowsAffected.size()][];
|
||||
for (int i = 0; i < result1.length; i++) {
|
||||
result1[i] = rowsAffected.get(i);
|
||||
}
|
||||
return result1;
|
||||
}
|
||||
finally {
|
||||
if (pss instanceof ParameterDisposer) {
|
||||
((ParameterDisposer) pss).cleanupParameters();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Assert.state(result != null, "No result array");
|
||||
return result;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -1015,7 +1019,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
logger.debug("Calling stored procedure" + (sql != null ? " [" + sql + "]" : ""));
|
||||
}
|
||||
|
||||
Connection con = DataSourceUtils.getConnection(getDataSource());
|
||||
Connection con = DataSourceUtils.getConnection(obtainDataSource());
|
||||
CallableStatement cs = null;
|
||||
try {
|
||||
cs = csc.createCallableStatement(con);
|
||||
@@ -1031,7 +1035,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
((ParameterDisposer) csc).cleanupParameters();
|
||||
}
|
||||
String sql = getSql(csc);
|
||||
csc = null;
|
||||
JdbcUtils.closeStatement(cs);
|
||||
cs = null;
|
||||
DataSourceUtils.releaseConnection(con, getDataSource());
|
||||
@@ -1059,6 +1062,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
final List<SqlParameter> updateCountParameters = new ArrayList<>();
|
||||
final List<SqlParameter> resultSetParameters = new ArrayList<>();
|
||||
final List<SqlParameter> callParameters = new ArrayList<>();
|
||||
|
||||
for (SqlParameter parameter : declaredParameters) {
|
||||
if (parameter.isResultsParameter()) {
|
||||
if (parameter instanceof SqlReturnResultSet) {
|
||||
@@ -1072,23 +1076,24 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
callParameters.add(parameter);
|
||||
}
|
||||
}
|
||||
return execute(csc, new CallableStatementCallback<Map<String, Object>>() {
|
||||
@Override
|
||||
public Map<String, Object> doInCallableStatement(CallableStatement cs) throws SQLException {
|
||||
boolean retVal = cs.execute();
|
||||
int updateCount = cs.getUpdateCount();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("CallableStatement.execute() returned '" + retVal + "'");
|
||||
logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
|
||||
}
|
||||
Map<String, Object> returnedResults = createResultsMap();
|
||||
if (retVal || updateCount != -1) {
|
||||
returnedResults.putAll(extractReturnedResults(cs, updateCountParameters, resultSetParameters, updateCount));
|
||||
}
|
||||
returnedResults.putAll(extractOutputParameters(cs, callParameters));
|
||||
return returnedResults;
|
||||
|
||||
Map<String, Object> result = execute(csc, cs -> {
|
||||
boolean retVal = cs.execute();
|
||||
int updateCount = cs.getUpdateCount();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("CallableStatement.execute() returned '" + retVal + "'");
|
||||
logger.debug("CallableStatement.getUpdateCount() returned " + updateCount);
|
||||
}
|
||||
Map<String, Object> returnedResults = createResultsMap();
|
||||
if (retVal || updateCount != -1) {
|
||||
returnedResults.putAll(extractReturnedResults(cs, updateCountParameters, resultSetParameters, updateCount));
|
||||
}
|
||||
returnedResults.putAll(extractOutputParameters(cs, callParameters));
|
||||
return returnedResults;
|
||||
});
|
||||
|
||||
Assert.state(result != null, "No result map");
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1099,8 +1104,8 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
* @return Map that contains returned results
|
||||
*/
|
||||
protected Map<String, Object> extractReturnedResults(CallableStatement cs,
|
||||
List<SqlParameter> updateCountParameters, List<SqlParameter> resultSetParameters, int updateCount)
|
||||
throws SQLException {
|
||||
@Nullable List<SqlParameter> updateCountParameters, @Nullable List<SqlParameter> resultSetParameters,
|
||||
int updateCount) throws SQLException {
|
||||
|
||||
Map<String, Object> returnedResults = new HashMap<>();
|
||||
int rsIndex = 0;
|
||||
@@ -1169,9 +1174,10 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
for (SqlParameter param : parameters) {
|
||||
if (param instanceof SqlOutParameter) {
|
||||
SqlOutParameter outParam = (SqlOutParameter) param;
|
||||
if (outParam.isReturnTypeSupported()) {
|
||||
Object out = outParam.getSqlReturnType().getTypeValue(
|
||||
cs, sqlColIndex, outParam.getSqlType(), outParam.getTypeName());
|
||||
Assert.state(outParam.getName() != null, "Anonymous parameters not allowed");
|
||||
SqlReturnType returnType = outParam.getSqlReturnType();
|
||||
if (returnType != null) {
|
||||
Object out = returnType.getTypeValue(cs, sqlColIndex, outParam.getSqlType(), outParam.getTypeName());
|
||||
returnedResults.put(outParam.getName(), out);
|
||||
}
|
||||
else {
|
||||
@@ -1207,16 +1213,18 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
* @param param the corresponding stored procedure parameter
|
||||
* @return Map that contains returned results
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
protected Map<String, Object> processResultSet(ResultSet rs, ResultSetSupportingSqlParameter param) throws SQLException {
|
||||
protected Map<String, Object> processResultSet(
|
||||
@Nullable ResultSet rs, ResultSetSupportingSqlParameter param) throws SQLException {
|
||||
|
||||
if (rs == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, Object> returnedResults = new HashMap<>();
|
||||
try {
|
||||
if (param.getRowMapper() != null) {
|
||||
RowMapper rowMapper = param.getRowMapper();
|
||||
Object result = (new RowMapperResultSetExtractor(rowMapper)).extractData(rs);
|
||||
RowMapper<?> rowMapper = param.getRowMapper();
|
||||
Object result = (new RowMapperResultSetExtractor<>(rowMapper)).extractData(rs);
|
||||
returnedResults.put(param.getName(), result);
|
||||
}
|
||||
else if (param.getRowCallbackHandler() != null) {
|
||||
@@ -1306,7 +1314,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
* @param args object array with arguments
|
||||
* @return the new PreparedStatementSetter to use
|
||||
*/
|
||||
protected PreparedStatementSetter newArgPreparedStatementSetter(Object[] args) {
|
||||
protected PreparedStatementSetter newArgPreparedStatementSetter(@Nullable Object[] args) {
|
||||
return new ArgumentPreparedStatementSetter(args);
|
||||
}
|
||||
|
||||
@@ -1357,6 +1365,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine SQL from potential provider object.
|
||||
* @param sqlProvider object that's potentially a SqlProvider
|
||||
@@ -1373,6 +1382,16 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
||||
}
|
||||
}
|
||||
|
||||
private static <T> T nonNull(@Nullable T result) {
|
||||
Assert.state(result != null, "No result");
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int updateCount(@Nullable Integer result) {
|
||||
Assert.state(result != null, "No update count");
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Invocation handler that suppresses close calls on JDBC Connections.
|
||||
|
||||
@@ -60,7 +60,7 @@ public class ResultSetSupportingSqlParameter extends SqlParameter {
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public ResultSetSupportingSqlParameter(String name, int sqlType, String typeName) {
|
||||
public ResultSetSupportingSqlParameter(String name, int sqlType, @Nullable String typeName) {
|
||||
super(name, sqlType, typeName);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.jdbc.core;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* An interface used by {@link JdbcTemplate} for mapping rows of a
|
||||
* {@link java.sql.ResultSet} on a per-row basis. Implementations of this
|
||||
@@ -58,6 +60,7 @@ public interface RowMapper<T> {
|
||||
* @throws SQLException if a SQLException is encountered getting
|
||||
* column values (that is, there's no need to catch SQLException)
|
||||
*/
|
||||
@Nullable
|
||||
T mapRow(ResultSet rs, int rowNum) throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -126,6 +126,7 @@ public class SingleColumnRowMapper<T> implements RowMapper<T> {
|
||||
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int, Class)
|
||||
* @see #getColumnValue(java.sql.ResultSet, int)
|
||||
*/
|
||||
@Nullable
|
||||
protected Object getColumnValue(ResultSet rs, int index, @Nullable Class<?> requiredType) throws SQLException {
|
||||
if (requiredType != null) {
|
||||
return JdbcUtils.getResultSetValue(rs, index, requiredType);
|
||||
@@ -150,6 +151,7 @@ public class SingleColumnRowMapper<T> implements RowMapper<T> {
|
||||
* @throws SQLException in case of extraction failure
|
||||
* @see org.springframework.jdbc.support.JdbcUtils#getResultSetValue(java.sql.ResultSet, int)
|
||||
*/
|
||||
@Nullable
|
||||
protected Object getColumnValue(ResultSet rs, int index) throws SQLException {
|
||||
return JdbcUtils.getResultSetValue(rs, index);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -63,7 +63,7 @@ public class SqlOutParameter extends ResultSetSupportingSqlParameter {
|
||||
* @param sqlType SQL type of the parameter according to java.sql.Types
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType, String typeName) {
|
||||
public SqlOutParameter(String name, int sqlType, @Nullable String typeName) {
|
||||
super(name, sqlType, typeName);
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ public class SqlOutParameter extends ResultSetSupportingSqlParameter {
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
* @param sqlReturnType custom value handler for complex type (optional)
|
||||
*/
|
||||
public SqlOutParameter(String name, int sqlType, String typeName, SqlReturnType sqlReturnType) {
|
||||
public SqlOutParameter(String name, int sqlType, @Nullable String typeName, @Nullable SqlReturnType sqlReturnType) {
|
||||
super(name, sqlType, typeName);
|
||||
this.sqlReturnType = sqlReturnType;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -61,7 +61,7 @@ public class SqlParameter {
|
||||
* @param sqlType SQL type of the parameter according to {@code java.sql.Types}
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public SqlParameter(int sqlType, String typeName) {
|
||||
public SqlParameter(int sqlType, @Nullable String typeName) {
|
||||
this.sqlType = sqlType;
|
||||
this.typeName = typeName;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ public class SqlParameter {
|
||||
* @param sqlType SQL type of the parameter according to {@code java.sql.Types}
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
*/
|
||||
public SqlParameter(String name, int sqlType, String typeName) {
|
||||
public SqlParameter(String name, int sqlType, @Nullable String typeName) {
|
||||
this.name = name;
|
||||
this.sqlType = sqlType;
|
||||
this.typeName = typeName;
|
||||
@@ -180,7 +180,7 @@ public class SqlParameter {
|
||||
* Convert a list of JDBC types, as defined in {@code java.sql.Types},
|
||||
* to a List of SqlParameter objects as used in this package.
|
||||
*/
|
||||
public static List<SqlParameter> sqlTypesToAnonymousParameterList(int... types) {
|
||||
public static List<SqlParameter> sqlTypesToAnonymousParameterList(@Nullable int... types) {
|
||||
List<SqlParameter> result = new LinkedList<>();
|
||||
if (types != null) {
|
||||
for (int type : types) {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.jdbc.core;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Object to represent a SQL parameter value, including parameter metadata
|
||||
* such as the SQL type and the scale for numeric values.
|
||||
@@ -44,7 +46,7 @@ public class SqlParameterValue extends SqlParameter {
|
||||
* @param sqlType SQL type of the parameter according to {@code java.sql.Types}
|
||||
* @param value the value object
|
||||
*/
|
||||
public SqlParameterValue(int sqlType, Object value) {
|
||||
public SqlParameterValue(int sqlType, @Nullable Object value) {
|
||||
super(sqlType);
|
||||
this.value = value;
|
||||
}
|
||||
@@ -55,7 +57,7 @@ public class SqlParameterValue extends SqlParameter {
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
* @param value the value object
|
||||
*/
|
||||
public SqlParameterValue(int sqlType, String typeName, Object value) {
|
||||
public SqlParameterValue(int sqlType, @Nullable String typeName, @Nullable Object value) {
|
||||
super(sqlType, typeName);
|
||||
this.value = value;
|
||||
}
|
||||
@@ -67,7 +69,7 @@ public class SqlParameterValue extends SqlParameter {
|
||||
* (for DECIMAL and NUMERIC types)
|
||||
* @param value the value object
|
||||
*/
|
||||
public SqlParameterValue(int sqlType, int scale, Object value) {
|
||||
public SqlParameterValue(int sqlType, int scale, @Nullable Object value) {
|
||||
super(sqlType, scale);
|
||||
this.value = value;
|
||||
}
|
||||
@@ -77,7 +79,7 @@ public class SqlParameterValue extends SqlParameter {
|
||||
* @param declaredParam the declared SqlParameter to define a value for
|
||||
* @param value the value object
|
||||
*/
|
||||
public SqlParameterValue(SqlParameter declaredParam, Object value) {
|
||||
public SqlParameterValue(SqlParameter declaredParam, @Nullable Object value) {
|
||||
super(declaredParam);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.jdbc.core;
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface to be implemented for retrieving values for more complex database-specific
|
||||
* types not supported by the standard {@code CallableStatement.getObject} method.
|
||||
@@ -52,14 +54,14 @@ public interface SqlReturnType {
|
||||
* @param cs the CallableStatement to operate on
|
||||
* @param paramIndex the index of the parameter for which we need to set the value
|
||||
* @param sqlType SQL type of the parameter we are setting
|
||||
* @param typeName the type name of the parameter
|
||||
* @param typeName the type name of the parameter (optional)
|
||||
* @return the target value
|
||||
* @throws SQLException if a SQLException is encountered setting parameter values
|
||||
* (that is, there's no need to catch SQLException)
|
||||
* @see java.sql.Types
|
||||
* @see java.sql.CallableStatement#getObject
|
||||
*/
|
||||
Object getTypeValue(CallableStatement cs, int paramIndex, int sqlType, String typeName)
|
||||
Object getTypeValue(CallableStatement cs, int paramIndex, int sqlType, @Nullable String typeName)
|
||||
throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,6 +20,7 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Interface to be implemented for setting values for more complex database-specific
|
||||
@@ -62,6 +63,7 @@ public interface SqlTypeValue {
|
||||
* @see java.sql.Types
|
||||
* @see java.sql.PreparedStatement#setObject
|
||||
*/
|
||||
void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName) throws SQLException;
|
||||
void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, @Nullable String typeName)
|
||||
throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -112,7 +112,10 @@ public abstract class StatementCreatorUtils {
|
||||
* @param javaType the Java type to translate
|
||||
* @return the corresponding SQL type, or {@link SqlTypeValue#TYPE_UNKNOWN} if none found
|
||||
*/
|
||||
public static int javaTypeToSqlParameterType(Class<?> javaType) {
|
||||
public static int javaTypeToSqlParameterType(@Nullable Class<?> javaType) {
|
||||
if (javaType == null) {
|
||||
return SqlTypeValue.TYPE_UNKNOWN;
|
||||
}
|
||||
Integer sqlType = javaTypeToSqlTypeMap.get(javaType);
|
||||
if (sqlType != null) {
|
||||
return sqlType;
|
||||
@@ -193,7 +196,7 @@ public abstract class StatementCreatorUtils {
|
||||
* @see SqlTypeValue
|
||||
*/
|
||||
private static void setParameterValueInternal(PreparedStatement ps, int paramIndex, int sqlType,
|
||||
@Nullable String typeName, @Nullable Integer scale, Object inValue) throws SQLException {
|
||||
@Nullable String typeName, @Nullable Integer scale, @Nullable Object inValue) throws SQLException {
|
||||
|
||||
String typeNameToUse = typeName;
|
||||
int sqlTypeToUse = sqlType;
|
||||
@@ -234,7 +237,9 @@ public abstract class StatementCreatorUtils {
|
||||
* Set the specified PreparedStatement parameter to null,
|
||||
* respecting database-specific peculiarities.
|
||||
*/
|
||||
private static void setNull(PreparedStatement ps, int paramIndex, int sqlType, String typeName) throws SQLException {
|
||||
private static void setNull(PreparedStatement ps, int paramIndex, int sqlType, @Nullable String typeName)
|
||||
throws SQLException {
|
||||
|
||||
if (sqlType == SqlTypeValue.TYPE_UNKNOWN || sqlType == Types.OTHER) {
|
||||
boolean useSetObject = false;
|
||||
Integer sqlTypeToUse = null;
|
||||
@@ -274,8 +279,8 @@ public abstract class StatementCreatorUtils {
|
||||
}
|
||||
}
|
||||
|
||||
private static void setValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName,
|
||||
Integer scale, Object inValue) throws SQLException {
|
||||
private static void setValue(PreparedStatement ps, int paramIndex, int sqlType,
|
||||
@Nullable String typeName, @Nullable Integer scale, Object inValue) throws SQLException {
|
||||
|
||||
if (inValue instanceof SqlTypeValue) {
|
||||
((SqlTypeValue) inValue).setTypeValue(ps, paramIndex, sqlType, typeName);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -39,6 +39,7 @@ import org.springframework.jdbc.core.SqlReturnResultSet;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -143,6 +144,7 @@ public class CallMetaDataContext {
|
||||
/**
|
||||
* Get the name of the procedure.
|
||||
*/
|
||||
@Nullable
|
||||
public String getProcedureName() {
|
||||
return this.procedureName;
|
||||
}
|
||||
@@ -157,6 +159,7 @@ public class CallMetaDataContext {
|
||||
/**
|
||||
* Get the name of the catalog.
|
||||
*/
|
||||
@Nullable
|
||||
public String getCatalogName() {
|
||||
return this.catalogName;
|
||||
}
|
||||
@@ -171,6 +174,7 @@ public class CallMetaDataContext {
|
||||
/**
|
||||
* Get the name of the schema.
|
||||
*/
|
||||
@Nullable
|
||||
public String getSchemaName() {
|
||||
return this.schemaName;
|
||||
}
|
||||
@@ -259,6 +263,7 @@ public class CallMetaDataContext {
|
||||
* Get the name of the single out parameter for this call.
|
||||
* If there are multiple parameters, the name of the first one will be returned.
|
||||
*/
|
||||
@Nullable
|
||||
public String getScalarOutParameterName() {
|
||||
if (isFunction()) {
|
||||
return getFunctionReturnName();
|
||||
@@ -309,7 +314,7 @@ public class CallMetaDataContext {
|
||||
// Get the names of the meta data parameters
|
||||
for (CallParameterMetaData meta : this.metaDataProvider.getCallParameterMetaData()) {
|
||||
if (meta.getParameterType() != DatabaseMetaData.procedureColumnReturn) {
|
||||
metaDataParamNames.add(meta.getParameterName().toLowerCase());
|
||||
metaDataParamNames.add(lowerCase(meta.getParameterName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -324,7 +329,7 @@ public class CallMetaDataContext {
|
||||
throw new IllegalArgumentException("Anonymous parameters not supported for calls - " +
|
||||
"please specify a name for the parameter of SQL type " + param.getSqlType());
|
||||
}
|
||||
String paramNameToMatch = this.metaDataProvider.parameterNameToUse(paramName).toLowerCase();
|
||||
String paramNameToMatch = lowerCase(this.metaDataProvider.parameterNameToUse(paramName));
|
||||
declaredParams.put(paramNameToMatch, param);
|
||||
if (param instanceof SqlOutParameter) {
|
||||
outParamNames.add(paramName);
|
||||
@@ -354,15 +359,16 @@ public class CallMetaDataContext {
|
||||
Map<String, String> limitedInParamNamesMap = new HashMap<>(this.limitedInParameterNames.size());
|
||||
for (String limitedParamName : this.limitedInParameterNames) {
|
||||
limitedInParamNamesMap.put(
|
||||
this.metaDataProvider.parameterNameToUse(limitedParamName).toLowerCase(), limitedParamName);
|
||||
lowerCase(this.metaDataProvider.parameterNameToUse(limitedParamName)), limitedParamName);
|
||||
}
|
||||
|
||||
for (CallParameterMetaData meta : this.metaDataProvider.getCallParameterMetaData()) {
|
||||
String paramName = meta.getParameterName();
|
||||
String paramNameToCheck = null;
|
||||
if (meta.getParameterName() != null) {
|
||||
paramNameToCheck = this.metaDataProvider.parameterNameToUse(meta.getParameterName()).toLowerCase();
|
||||
if (paramName != null) {
|
||||
paramNameToCheck = lowerCase(this.metaDataProvider.parameterNameToUse(paramName));
|
||||
}
|
||||
String paramNameToUse = this.metaDataProvider.parameterNameToUse(meta.getParameterName());
|
||||
String paramNameToUse = this.metaDataProvider.parameterNameToUse(paramName);
|
||||
if (declaredParams.containsKey(paramNameToCheck) ||
|
||||
(meta.getParameterType() == DatabaseMetaData.procedureColumnReturn && returnDeclared)) {
|
||||
SqlParameter param;
|
||||
@@ -376,8 +382,8 @@ public class CallMetaDataContext {
|
||||
"Unable to locate declared parameter for function return value - " +
|
||||
" add a SqlOutParameter with name '" + getFunctionReturnName() + "'");
|
||||
}
|
||||
else {
|
||||
setFunctionReturnName(param.getName());
|
||||
else if (paramName != null) {
|
||||
setFunctionReturnName(paramName);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -393,15 +399,15 @@ public class CallMetaDataContext {
|
||||
}
|
||||
else {
|
||||
if (meta.getParameterType() == DatabaseMetaData.procedureColumnReturn) {
|
||||
if (!isFunction() && !isReturnValueRequired() &&
|
||||
this.metaDataProvider.byPassReturnParameter(meta.getParameterName())) {
|
||||
if (!isFunction() && !isReturnValueRequired() && paramName != null &&
|
||||
this.metaDataProvider.byPassReturnParameter(paramName)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Bypassing metadata return parameter for '" + meta.getParameterName() + "'");
|
||||
logger.debug("Bypassing metadata return parameter for '" + paramName + "'");
|
||||
}
|
||||
}
|
||||
else {
|
||||
String returnNameToUse =(StringUtils.hasLength(meta.getParameterName()) ?
|
||||
paramNameToUse : getFunctionReturnName());
|
||||
String returnNameToUse =
|
||||
(StringUtils.hasLength(paramNameToUse) ? paramNameToUse : getFunctionReturnName());
|
||||
workParams.add(this.metaDataProvider.createDefaultOutParameter(returnNameToUse, meta));
|
||||
if (isFunction()) {
|
||||
setFunctionReturnName(returnNameToUse);
|
||||
@@ -413,6 +419,9 @@ public class CallMetaDataContext {
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (paramNameToUse == null) {
|
||||
paramNameToUse = "";
|
||||
}
|
||||
if (meta.getParameterType() == DatabaseMetaData.procedureColumnOut) {
|
||||
workParams.add(this.metaDataProvider.createDefaultOutParameter(paramNameToUse, meta));
|
||||
outParamNames.add(paramNameToUse);
|
||||
@@ -429,7 +438,7 @@ public class CallMetaDataContext {
|
||||
}
|
||||
else {
|
||||
if (this.limitedInParameterNames.isEmpty() ||
|
||||
limitedInParamNamesMap.containsKey(paramNameToUse.toLowerCase())) {
|
||||
limitedInParamNamesMap.containsKey(lowerCase(paramNameToUse))) {
|
||||
workParams.add(this.metaDataProvider.createDefaultInParameter(paramNameToUse, meta));
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Added metadata in parameter for '" + paramNameToUse + "'");
|
||||
@@ -534,7 +543,7 @@ public class CallMetaDataContext {
|
||||
Map<String, Object> matchedParameters = new HashMap<>(inParameters.size());
|
||||
for (String parameterName : inParameters.keySet()) {
|
||||
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
|
||||
String callParameterName = callParameterNames.get(parameterNameToMatch.toLowerCase());
|
||||
String callParameterName = callParameterNames.get(lowerCase(parameterNameToMatch));
|
||||
if (callParameterName == null) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
Object value = inParameters.get(parameterName);
|
||||
@@ -554,7 +563,7 @@ public class CallMetaDataContext {
|
||||
if (matchedParameters.size() < callParameterNames.size()) {
|
||||
for (String parameterName : callParameterNames.keySet()) {
|
||||
String parameterNameToMatch = this.metaDataProvider.parameterNameToUse(parameterName);
|
||||
String callParameterName = callParameterNames.get(parameterNameToMatch.toLowerCase());
|
||||
String callParameterName = callParameterNames.get(lowerCase(parameterNameToMatch));
|
||||
if (!matchedParameters.containsKey(callParameterName)) {
|
||||
logger.warn("Unable to locate the corresponding parameter value for '" + parameterName +
|
||||
"' within the parameter values provided: " + inParameters.keySet());
|
||||
@@ -646,4 +655,8 @@ public class CallMetaDataContext {
|
||||
}
|
||||
}
|
||||
|
||||
private static String lowerCase(@Nullable String paramName) {
|
||||
return (paramName != null ? paramName.toLowerCase() : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -52,30 +52,29 @@ public interface CallMetaDataProvider {
|
||||
* @throws SQLException in case of initialization failure
|
||||
* @see org.springframework.jdbc.core.simple.SimpleJdbcCall#withoutProcedureColumnMetaDataAccess()
|
||||
*/
|
||||
void initializeWithProcedureColumnMetaData(
|
||||
DatabaseMetaData databaseMetaData, @Nullable String catalogName, @Nullable String schemaName, String procedureName)
|
||||
throws SQLException;
|
||||
void initializeWithProcedureColumnMetaData(DatabaseMetaData databaseMetaData, @Nullable String catalogName,
|
||||
@Nullable String schemaName, @Nullable String procedureName) throws SQLException;
|
||||
|
||||
/**
|
||||
* Provide any modification of the procedure name passed in to match the meta data currently used.
|
||||
* This could include altering the case.
|
||||
*/
|
||||
@Nullable
|
||||
String procedureNameToUse(String procedureName);
|
||||
String procedureNameToUse(@Nullable String procedureName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the catalog name passed in to match the meta data currently used.
|
||||
* This could include altering the case.
|
||||
*/
|
||||
@Nullable
|
||||
String catalogNameToUse(String catalogName);
|
||||
String catalogNameToUse(@Nullable String catalogName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the schema name passed in to match the meta data currently used.
|
||||
* This could include altering the case.
|
||||
*/
|
||||
@Nullable
|
||||
String schemaNameToUse(String schemaName);
|
||||
String schemaNameToUse(@Nullable String schemaName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the catalog name passed in to match the meta data currently used.
|
||||
@@ -83,7 +82,7 @@ public interface CallMetaDataProvider {
|
||||
* used or providing a base catalog if none is provided.
|
||||
*/
|
||||
@Nullable
|
||||
String metaDataCatalogNameToUse(String catalogName) ;
|
||||
String metaDataCatalogNameToUse(@Nullable String catalogName) ;
|
||||
|
||||
/**
|
||||
* Provide any modification of the schema name passed in to match the meta data currently used.
|
||||
@@ -91,14 +90,15 @@ public interface CallMetaDataProvider {
|
||||
* used or providing a base schema if none is provided.
|
||||
*/
|
||||
@Nullable
|
||||
String metaDataSchemaNameToUse(String schemaName) ;
|
||||
String metaDataSchemaNameToUse(@Nullable String schemaName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the column name passed in to match the meta data currently used.
|
||||
* This could include altering the case.
|
||||
* @param parameterName name of the parameter of column
|
||||
*/
|
||||
String parameterNameToUse(String parameterName);
|
||||
@Nullable
|
||||
String parameterNameToUse(@Nullable String parameterName);
|
||||
|
||||
/**
|
||||
* Create a default out parameter based on the provided meta data.
|
||||
@@ -131,6 +131,7 @@ public interface CallMetaDataProvider {
|
||||
* Get the name of the current user. Useful for meta data lookups etc.
|
||||
* @return current user name from database connection
|
||||
*/
|
||||
@Nullable
|
||||
String getUserName();
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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,8 +16,6 @@
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import javax.sql.DataSource;
|
||||
@@ -26,9 +24,9 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.jdbc.support.DatabaseMetaDataCallback;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Factory used to create a {@link CallMetaDataProvider} implementation
|
||||
@@ -70,72 +68,70 @@ public class CallMetaDataProviderFactory {
|
||||
*/
|
||||
static public CallMetaDataProvider createMetaDataProvider(DataSource dataSource, final CallMetaDataContext context) {
|
||||
try {
|
||||
return (CallMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource, new DatabaseMetaDataCallback() {
|
||||
@Override
|
||||
public Object processMetaData(DatabaseMetaData databaseMetaData) throws SQLException, MetaDataAccessException {
|
||||
String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessProcedureColumnMetaData = context.isAccessCallParameterMetaData();
|
||||
if (context.isFunction()) {
|
||||
if (!supportedDatabaseProductsForFunctions.contains(databaseProductName)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(databaseProductName + " is not one of the databases fully supported for function calls " +
|
||||
"-- supported are: " + supportedDatabaseProductsForFunctions);
|
||||
}
|
||||
if (accessProcedureColumnMetaData) {
|
||||
logger.warn("Metadata processing disabled - you must specify all parameters explicitly");
|
||||
accessProcedureColumnMetaData = false;
|
||||
}
|
||||
CallMetaDataProvider result = (CallMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource, databaseMetaData -> {
|
||||
String databaseProductName = JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessProcedureColumnMetaData = context.isAccessCallParameterMetaData();
|
||||
if (context.isFunction()) {
|
||||
if (!supportedDatabaseProductsForFunctions.contains(databaseProductName)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(databaseProductName + " is not one of the databases fully supported for function calls " +
|
||||
"-- supported are: " + supportedDatabaseProductsForFunctions);
|
||||
}
|
||||
if (accessProcedureColumnMetaData) {
|
||||
logger.warn("Metadata processing disabled - you must specify all parameters explicitly");
|
||||
accessProcedureColumnMetaData = false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!supportedDatabaseProductsForProcedures.contains(databaseProductName)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(databaseProductName + " is not one of the databases fully supported for procedure calls " +
|
||||
"-- supported are: " + supportedDatabaseProductsForProcedures);
|
||||
}
|
||||
if (accessProcedureColumnMetaData) {
|
||||
logger.warn("Metadata processing disabled - you must specify all parameters explicitly");
|
||||
accessProcedureColumnMetaData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CallMetaDataProvider provider;
|
||||
if ("Oracle".equals(databaseProductName)) {
|
||||
provider = new OracleCallMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("DB2".equals(databaseProductName)) {
|
||||
provider = new Db2CallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
provider = new DerbyCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("PostgreSQL".equals(databaseProductName)) {
|
||||
provider = new PostgresCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Sybase".equals(databaseProductName)) {
|
||||
provider = new SybaseCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Microsoft SQL Server".equals(databaseProductName)) {
|
||||
provider = new SqlServerCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("HDB".equals(databaseProductName)) {
|
||||
provider = new HanaCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else {
|
||||
provider = new GenericCallMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessProcedureColumnMetaData) {
|
||||
provider.initializeWithProcedureColumnMetaData(databaseMetaData,
|
||||
context.getCatalogName(), context.getSchemaName(), context.getProcedureName());
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
else {
|
||||
if (!supportedDatabaseProductsForProcedures.contains(databaseProductName)) {
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn(databaseProductName + " is not one of the databases fully supported for procedure calls " +
|
||||
"-- supported are: " + supportedDatabaseProductsForProcedures);
|
||||
}
|
||||
if (accessProcedureColumnMetaData) {
|
||||
logger.warn("Metadata processing disabled - you must specify all parameters explicitly");
|
||||
accessProcedureColumnMetaData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
CallMetaDataProvider provider;
|
||||
if ("Oracle".equals(databaseProductName)) {
|
||||
provider = new OracleCallMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("DB2".equals(databaseProductName)) {
|
||||
provider = new Db2CallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
provider = new DerbyCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("PostgreSQL".equals(databaseProductName)) {
|
||||
provider = new PostgresCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Sybase".equals(databaseProductName)) {
|
||||
provider = new SybaseCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("Microsoft SQL Server".equals(databaseProductName)) {
|
||||
provider = new SqlServerCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else if ("HDB".equals(databaseProductName)) {
|
||||
provider = new HanaCallMetaDataProvider((databaseMetaData));
|
||||
}
|
||||
else {
|
||||
provider = new GenericCallMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessProcedureColumnMetaData) {
|
||||
provider.initializeWithProcedureColumnMetaData(databaseMetaData,
|
||||
context.getCatalogName(), context.getSchemaName(), context.getProcedureName());
|
||||
}
|
||||
return provider;
|
||||
});
|
||||
Assert.state(result != null, "No CallMetaDataProvider");
|
||||
return result;
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
throw new DataAccessResourceFailureException("Error retrieving database metadata", ex);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Holder of metadata for a specific parameter that is used for call processing.
|
||||
*
|
||||
@@ -39,7 +41,9 @@ public class CallParameterMetaData {
|
||||
/**
|
||||
* Constructor taking all the properties.
|
||||
*/
|
||||
public CallParameterMetaData(String columnName, int columnType, int sqlType, String typeName, boolean nullable) {
|
||||
public CallParameterMetaData(
|
||||
@Nullable String columnName, int columnType, int sqlType, @Nullable String typeName, boolean nullable) {
|
||||
|
||||
this.parameterName = columnName;
|
||||
this.parameterType = columnType;
|
||||
this.sqlType = sqlType;
|
||||
@@ -51,6 +55,7 @@ public class CallParameterMetaData {
|
||||
/**
|
||||
* Get the parameter name.
|
||||
*/
|
||||
@Nullable
|
||||
public String getParameterName() {
|
||||
return this.parameterName;
|
||||
}
|
||||
@@ -72,6 +77,7 @@ public class CallParameterMetaData {
|
||||
/**
|
||||
* Get the parameter type name.
|
||||
*/
|
||||
@Nullable
|
||||
public String getTypeName() {
|
||||
return this.typeName;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.jdbc.core.metadata;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* DB2 specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
@@ -39,31 +41,31 @@ public class Db2CallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
try {
|
||||
setSupportsCatalogsInProcedureCalls(databaseMetaData.supportsCatalogsInProcedureCalls());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.supportsCatalogsInProcedureCalls' - " + se.getMessage());
|
||||
catch (SQLException ex) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.supportsCatalogsInProcedureCalls' - " + ex.getMessage());
|
||||
}
|
||||
try {
|
||||
setSupportsSchemasInProcedureCalls(databaseMetaData.supportsSchemasInProcedureCalls());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.supportsSchemasInProcedureCalls' - " + se.getMessage());
|
||||
catch (SQLException ex) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.supportsSchemasInProcedureCalls' - " + ex.getMessage());
|
||||
}
|
||||
try {
|
||||
setStoresUpperCaseIdentifiers(databaseMetaData.storesUpperCaseIdentifiers());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.storesUpperCaseIdentifiers' - " + se.getMessage());
|
||||
catch (SQLException ex) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.storesUpperCaseIdentifiers' - " + ex.getMessage());
|
||||
}
|
||||
try {
|
||||
setStoresLowerCaseIdentifiers(databaseMetaData.storesLowerCaseIdentifiers());
|
||||
}
|
||||
catch (SQLException se) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers' - " + se.getMessage());
|
||||
catch (SQLException ex) {
|
||||
logger.debug("Error retrieving 'DatabaseMetaData.storesLowerCaseIdentifiers' - " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
public String metaDataSchemaNameToUse(@Nullable String schemaName) {
|
||||
if (schemaName != null) {
|
||||
return super.metaDataSchemaNameToUse(schemaName);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2010 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.jdbc.core.metadata;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Derby specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
@@ -34,7 +36,7 @@ public class DerbyCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
public String metaDataSchemaNameToUse(@Nullable String schemaName) {
|
||||
if (schemaName != null) {
|
||||
return super.metaDataSchemaNameToUse(schemaName);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -21,8 +21,8 @@ import java.sql.SQLException;
|
||||
|
||||
/**
|
||||
* The Derby specific implementation of the {@link org.springframework.jdbc.core.metadata.TableMetaDataProvider}.
|
||||
* Overrides the Derby metadata info regarding retreiving generated keys. It seems to work OK so not sure why they
|
||||
* claim it's not supported.
|
||||
* Overrides the Derby metadata info regarding retrieving generated keys. It seems to work OK so not sure why
|
||||
* they claim it's not supported.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 3.0
|
||||
@@ -31,26 +31,26 @@ public class DerbyTableMetaDataProvider extends GenericTableMetaDataProvider {
|
||||
|
||||
private boolean supportsGeneratedKeysOverride = false;
|
||||
|
||||
|
||||
public DerbyTableMetaDataProvider(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super(databaseMetaData);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void initializeWithMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
super.initializeWithMetaData(databaseMetaData);
|
||||
if (!databaseMetaData.supportsGetGeneratedKeys()) {
|
||||
logger.warn("Overriding supportsGetGeneratedKeys from DatabaseMetaData to 'true'; it was reported as " +
|
||||
"'false' by " + databaseMetaData.getDriverName() + " " + databaseMetaData.getDriverVersion());
|
||||
supportsGeneratedKeysOverride = true;
|
||||
if (logger.isWarnEnabled()) {
|
||||
logger.warn("Overriding supportsGetGeneratedKeys from DatabaseMetaData to 'true'; it was reported as " +
|
||||
"'false' by " + databaseMetaData.getDriverName() + " " + databaseMetaData.getDriverVersion());
|
||||
}
|
||||
this.supportsGeneratedKeysOverride = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isGetGeneratedKeysSupported() {
|
||||
boolean derbysAnswer = super.isGetGeneratedKeysSupported();
|
||||
if (!derbysAnswer) {
|
||||
return supportsGeneratedKeysOverride;
|
||||
}
|
||||
return derbysAnswer;
|
||||
return (super.isGetGeneratedKeysSupported() || this.supportsGeneratedKeysOverride);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String procedureNameToUse(String procedureName) {
|
||||
public String procedureNameToUse(@Nullable String procedureName) {
|
||||
if (procedureName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -135,7 +135,7 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String catalogNameToUse(String catalogName) {
|
||||
public String catalogNameToUse(@Nullable String catalogName) {
|
||||
if (catalogName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -151,7 +151,7 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String schemaNameToUse(String schemaName) {
|
||||
public String schemaNameToUse(@Nullable String schemaName) {
|
||||
if (schemaName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -167,7 +167,7 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataCatalogNameToUse(String catalogName) {
|
||||
public String metaDataCatalogNameToUse(@Nullable String catalogName) {
|
||||
if (isSupportsCatalogsInProcedureCalls()) {
|
||||
return catalogNameToUse(catalogName);
|
||||
}
|
||||
@@ -177,7 +177,7 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
public String metaDataSchemaNameToUse(@Nullable String schemaName) {
|
||||
if (isSupportsSchemasInProcedureCalls()) {
|
||||
return schemaNameToUse(schemaName);
|
||||
}
|
||||
@@ -187,7 +187,7 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String parameterNameToUse(String parameterName) {
|
||||
public String parameterNameToUse(@Nullable String parameterName) {
|
||||
if (parameterName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -310,8 +310,8 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
/**
|
||||
* Process the procedure column metadata
|
||||
*/
|
||||
private void processProcedureColumns(
|
||||
DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String procedureName) {
|
||||
private void processProcedureColumns(DatabaseMetaData databaseMetaData,
|
||||
@Nullable String catalogName, @Nullable String schemaName, @Nullable String procedureName) {
|
||||
|
||||
String metaDataCatalogName = metaDataCatalogNameToUse(catalogName);
|
||||
String metaDataSchemaName = metaDataSchemaNameToUse(schemaName);
|
||||
@@ -337,7 +337,8 @@ public class GenericCallMetaDataProvider implements CallMetaDataProvider {
|
||||
"procedures/functions/signatures for '" + metaDataProcedureName + "': found " + found);
|
||||
}
|
||||
else if (found.isEmpty()) {
|
||||
if (metaDataProcedureName.contains(".") && !StringUtils.hasText(metaDataCatalogName)) {
|
||||
if (metaDataProcedureName != null && metaDataProcedureName.contains(".") &&
|
||||
!StringUtils.hasText(metaDataCatalogName)) {
|
||||
String packageName = metaDataProcedureName.substring(0, metaDataProcedureName.indexOf("."));
|
||||
throw new InvalidDataAccessApiUsageException(
|
||||
"Unable to determine the correct call signature for '" + metaDataProcedureName +
|
||||
|
||||
@@ -214,14 +214,14 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
|
||||
@Override
|
||||
public void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, @Nullable String catalogName,
|
||||
@Nullable String schemaName, String tableName) throws SQLException {
|
||||
@Nullable String schemaName, @Nullable String tableName) throws SQLException {
|
||||
|
||||
this.tableColumnMetaDataUsed = true;
|
||||
locateTableAndProcessMetaData(databaseMetaData, catalogName, schemaName, tableName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String tableNameToUse(String tableName) {
|
||||
public String tableNameToUse(@Nullable String tableName) {
|
||||
if (tableName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -237,7 +237,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String catalogNameToUse(String catalogName) {
|
||||
public String catalogNameToUse(@Nullable String catalogName) {
|
||||
if (catalogName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -253,7 +253,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String schemaNameToUse(String schemaName) {
|
||||
public String schemaNameToUse(@Nullable String schemaName) {
|
||||
if (schemaName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -269,12 +269,12 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataCatalogNameToUse(String catalogName) {
|
||||
public String metaDataCatalogNameToUse(@Nullable String catalogName) {
|
||||
return catalogNameToUse(catalogName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
public String metaDataSchemaNameToUse(@Nullable String schemaName) {
|
||||
if (schemaName == null) {
|
||||
return schemaNameToUse(getDefaultSchema());
|
||||
}
|
||||
@@ -298,8 +298,8 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
/**
|
||||
* Method supporting the metadata processing for a table.
|
||||
*/
|
||||
private void locateTableAndProcessMetaData(
|
||||
DatabaseMetaData databaseMetaData, String catalogName, String schemaName, String tableName) {
|
||||
private void locateTableAndProcessMetaData(DatabaseMetaData databaseMetaData,
|
||||
@Nullable String catalogName, @Nullable String schemaName, @Nullable String tableName) {
|
||||
|
||||
Map<String, TableMetaData> tableMeta = new HashMap<>();
|
||||
ResultSet tables = null;
|
||||
@@ -338,7 +338,9 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
}
|
||||
}
|
||||
|
||||
private TableMetaData findTableMetaData(String schemaName, String tableName, Map<String, TableMetaData> tableMeta) {
|
||||
private TableMetaData findTableMetaData(@Nullable String schemaName, @Nullable String tableName,
|
||||
Map<String, TableMetaData> tableMeta) {
|
||||
|
||||
if (schemaName != null) {
|
||||
TableMetaData tmd = tableMeta.get(schemaName.toUpperCase());
|
||||
if (tmd == null) {
|
||||
@@ -435,6 +437,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
this.catalogName = catalogName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getCatalogName() {
|
||||
return this.catalogName;
|
||||
}
|
||||
@@ -443,6 +446,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
this.schemaName = schemaName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getSchemaName() {
|
||||
return this.schemaName;
|
||||
}
|
||||
@@ -451,6 +455,7 @@ public class GenericTableMetaDataProvider implements TableMetaDataProvider {
|
||||
this.tableName = tableName;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTableName() {
|
||||
return this.tableName;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -23,9 +23,10 @@ import java.sql.Types;
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
import org.springframework.jdbc.core.SqlOutParameter;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Oracle specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* Oracle-specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
@@ -57,15 +58,15 @@ public class OracleCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataCatalogNameToUse(String catalogName) {
|
||||
public String metaDataCatalogNameToUse(@Nullable String catalogName) {
|
||||
// Oracle uses catalog name for package name or an empty string if no package
|
||||
return catalogName == null ? "" : catalogNameToUse(catalogName);
|
||||
return (catalogName == null ? "" : catalogNameToUse(catalogName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
public String metaDataSchemaNameToUse(@Nullable String schemaName) {
|
||||
// Use current user schema if no schema specified
|
||||
return schemaName == null ? getUserName() : super.metaDataSchemaNameToUse(schemaName);
|
||||
return (schemaName == null ? getUserName() : super.metaDataSchemaNameToUse(schemaName));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -23,9 +23,10 @@ import java.sql.Types;
|
||||
import org.springframework.jdbc.core.ColumnMapRowMapper;
|
||||
import org.springframework.jdbc.core.SqlOutParameter;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Oracle specific implementation for the {@link org.springframework.jdbc.core.metadata.CallMetaDataProvider} interface.
|
||||
* Postgres-specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
@@ -57,9 +58,9 @@ public class PostgresCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String metaDataSchemaNameToUse(String schemaName) {
|
||||
public String metaDataSchemaNameToUse(@Nullable String schemaName) {
|
||||
// Use public schema if no schema specified
|
||||
return schemaName == null ? "public" : super.metaDataSchemaNameToUse(schemaName);
|
||||
return (schemaName == null ? "public" : super.metaDataSchemaNameToUse(schemaName));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -74,7 +75,6 @@ public class PostgresCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
@Override
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return (RETURN_VALUE_NAME.equals(parameterName) ||
|
||||
super.byPassReturnParameter(parameterName));
|
||||
return RETURN_VALUE_NAME.equals(parameterName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.jdbc.core.metadata;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* SQL Server specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
@@ -39,7 +41,7 @@ public class SqlServerCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
|
||||
@Override
|
||||
public String parameterNameToUse(String parameterName) {
|
||||
public String parameterNameToUse(@Nullable String parameterName) {
|
||||
if (parameterName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -53,7 +55,7 @@ public class SqlServerCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
@Override
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return (RETURN_VALUE_NAME.equals(parameterName) || super.byPassReturnParameter(parameterName));
|
||||
return RETURN_VALUE_NAME.equals(parameterName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2007 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -19,6 +19,8 @@ package org.springframework.jdbc.core.metadata;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Sybase specific implementation for the {@link CallMetaDataProvider} interface.
|
||||
* This class is intended for internal use by the Simple JDBC classes.
|
||||
@@ -39,7 +41,7 @@ public class SybaseCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
|
||||
|
||||
@Override
|
||||
public String parameterNameToUse(String parameterName) {
|
||||
public String parameterNameToUse(@Nullable String parameterName) {
|
||||
if (parameterName == null) {
|
||||
return null;
|
||||
}
|
||||
@@ -54,8 +56,7 @@ public class SybaseCallMetaDataProvider extends GenericCallMetaDataProvider {
|
||||
@Override
|
||||
public boolean byPassReturnParameter(String parameterName) {
|
||||
return (RETURN_VALUE_NAME.equals(parameterName) ||
|
||||
RETURN_VALUE_NAME.equals(parameterNameToUse(parameterName)) ||
|
||||
super.byPassReturnParameter(parameterName));
|
||||
RETURN_VALUE_NAME.equals(parameterNameToUse(parameterName)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.springframework.jdbc.core.SqlTypeValue;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Class to manage context metadata used for the configuration
|
||||
@@ -81,6 +82,7 @@ public class TableMetaDataContext {
|
||||
/**
|
||||
* Get the name of the table for this context.
|
||||
*/
|
||||
@Nullable
|
||||
public String getTableName() {
|
||||
return this.tableName;
|
||||
}
|
||||
@@ -95,6 +97,7 @@ public class TableMetaDataContext {
|
||||
/**
|
||||
* Get the name of the catalog for this context.
|
||||
*/
|
||||
@Nullable
|
||||
public String getCatalogName() {
|
||||
return this.catalogName;
|
||||
}
|
||||
@@ -109,6 +112,7 @@ public class TableMetaDataContext {
|
||||
/**
|
||||
* Get the name of the schema for this context.
|
||||
*/
|
||||
@Nullable
|
||||
public String getSchemaName() {
|
||||
return this.schemaName;
|
||||
}
|
||||
@@ -171,6 +175,7 @@ public class TableMetaDataContext {
|
||||
* when the JDBC 3.0 feature is not supported.
|
||||
* {@link java.sql.DatabaseMetaData#supportsGetGeneratedKeys()}?
|
||||
*/
|
||||
@Nullable
|
||||
public String getSimulationQueryForGetGeneratedKey(String tableName, String keyColumnName) {
|
||||
return this.metaDataProvider.getSimpleQueryForGetGeneratedKey(tableName, keyColumnName);
|
||||
}
|
||||
|
||||
@@ -47,38 +47,42 @@ public interface TableMetaDataProvider {
|
||||
* @param tableName name of the table
|
||||
* @throws SQLException in case of initialization failure
|
||||
*/
|
||||
void initializeWithTableColumnMetaData(
|
||||
DatabaseMetaData databaseMetaData, @Nullable String catalogName, @Nullable String schemaName, String tableName)
|
||||
throws SQLException;
|
||||
void initializeWithTableColumnMetaData(DatabaseMetaData databaseMetaData, @Nullable String catalogName,
|
||||
@Nullable String schemaName, @Nullable String tableName) throws SQLException;
|
||||
|
||||
/**
|
||||
* Get the table name formatted based on metadata information. This could include altering the case.
|
||||
*/
|
||||
String tableNameToUse(String tableName);
|
||||
@Nullable
|
||||
String tableNameToUse(@Nullable String tableName);
|
||||
|
||||
/**
|
||||
* Get the catalog name formatted based on metadata information. This could include altering the case.
|
||||
*/
|
||||
String catalogNameToUse(String catalogName);
|
||||
@Nullable
|
||||
String catalogNameToUse(@Nullable String catalogName);
|
||||
|
||||
/**
|
||||
* Get the schema name formatted based on metadata information. This could include altering the case.
|
||||
*/
|
||||
String schemaNameToUse(String schemaName);
|
||||
@Nullable
|
||||
String schemaNameToUse(@Nullable String schemaName);
|
||||
|
||||
/**
|
||||
* Provide any modification of the catalog name passed in to match the meta data currently used.
|
||||
* The returned value will be used for meta data lookups. This could include altering the case used or
|
||||
* providing a base catalog if none is provided.
|
||||
*/
|
||||
String metaDataCatalogNameToUse(String catalogName) ;
|
||||
@Nullable
|
||||
String metaDataCatalogNameToUse(@Nullable String catalogName) ;
|
||||
|
||||
/**
|
||||
* Provide any modification of the schema name passed in to match the meta data currently used.
|
||||
* The returned value will be used for meta data lookups. This could include altering the case used or
|
||||
* providing a base schema if none is provided.
|
||||
*/
|
||||
String metaDataSchemaNameToUse(String schemaName) ;
|
||||
@Nullable
|
||||
String metaDataSchemaNameToUse(@Nullable String schemaName) ;
|
||||
|
||||
/**
|
||||
* Are we using the meta data for the table columns?
|
||||
|
||||
@@ -16,17 +16,15 @@
|
||||
|
||||
package org.springframework.jdbc.core.metadata;
|
||||
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.SQLException;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.jdbc.support.DatabaseMetaDataCallback;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.MetaDataAccessException;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Factory used to create a {@link TableMetaDataProvider} implementation
|
||||
@@ -48,41 +46,39 @@ public class TableMetaDataProviderFactory {
|
||||
*/
|
||||
public static TableMetaDataProvider createMetaDataProvider(DataSource dataSource, TableMetaDataContext context) {
|
||||
try {
|
||||
return (TableMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource,
|
||||
new DatabaseMetaDataCallback() {
|
||||
@Override
|
||||
public Object processMetaData(DatabaseMetaData databaseMetaData) throws SQLException {
|
||||
String databaseProductName =
|
||||
JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessTableColumnMetaData = context.isAccessTableColumnMetaData();
|
||||
TableMetaDataProvider provider;
|
||||
if ("Oracle".equals(databaseProductName)) {
|
||||
provider = new OracleTableMetaDataProvider(databaseMetaData,
|
||||
context.isOverrideIncludeSynonymsDefault());
|
||||
}
|
||||
else if ("HSQL Database Engine".equals(databaseProductName)) {
|
||||
provider = new HsqlTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("PostgreSQL".equals(databaseProductName)) {
|
||||
provider = new PostgresTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
provider = new DerbyTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else {
|
||||
provider = new GenericTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getSimpleName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessTableColumnMetaData) {
|
||||
provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(),
|
||||
context.getSchemaName(), context.getTableName());
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
});
|
||||
TableMetaDataProvider result = (TableMetaDataProvider) JdbcUtils.extractDatabaseMetaData(dataSource, databaseMetaData -> {
|
||||
String databaseProductName =
|
||||
JdbcUtils.commonDatabaseName(databaseMetaData.getDatabaseProductName());
|
||||
boolean accessTableColumnMetaData = context.isAccessTableColumnMetaData();
|
||||
TableMetaDataProvider provider;
|
||||
if ("Oracle".equals(databaseProductName)) {
|
||||
provider = new OracleTableMetaDataProvider(databaseMetaData,
|
||||
context.isOverrideIncludeSynonymsDefault());
|
||||
}
|
||||
else if ("HSQL Database Engine".equals(databaseProductName)) {
|
||||
provider = new HsqlTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("PostgreSQL".equals(databaseProductName)) {
|
||||
provider = new PostgresTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else if ("Apache Derby".equals(databaseProductName)) {
|
||||
provider = new DerbyTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
else {
|
||||
provider = new GenericTableMetaDataProvider(databaseMetaData);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Using " + provider.getClass().getSimpleName());
|
||||
}
|
||||
provider.initializeWithMetaData(databaseMetaData);
|
||||
if (accessTableColumnMetaData) {
|
||||
provider.initializeWithTableColumnMetaData(databaseMetaData, context.getCatalogName(),
|
||||
context.getSchemaName(), context.getTableName());
|
||||
}
|
||||
return provider;
|
||||
});
|
||||
Assert.state(result != null, "No TableMetaDataProvider");
|
||||
return result;
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
throw new DataAccessResourceFailureException("Error retrieving database metadata", ex);
|
||||
|
||||
@@ -117,6 +117,7 @@ public interface NamedParameterJdbcOperations {
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if the query fails
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, SqlParameterSource paramSource, ResultSetExtractor<T> rse)
|
||||
throws DataAccessException;
|
||||
|
||||
@@ -131,6 +132,7 @@ public interface NamedParameterJdbcOperations {
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, Map<String, ?> paramMap, ResultSetExtractor<T> rse)
|
||||
throws DataAccessException;
|
||||
|
||||
@@ -145,6 +147,7 @@ public interface NamedParameterJdbcOperations {
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws org.springframework.dao.DataAccessException if the query fails
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, ResultSetExtractor<T> rse) throws DataAccessException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -274,8 +274,10 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
|
||||
|
||||
@Override
|
||||
public SqlRowSet queryForRowSet(String sql, SqlParameterSource paramSource) throws DataAccessException {
|
||||
return getJdbcOperations().query(
|
||||
SqlRowSet result = getJdbcOperations().query(
|
||||
getPreparedStatementCreator(sql, paramSource), new SqlRowSetResultSetExtractor());
|
||||
Assert.state(result != null, "No result");
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -354,7 +354,9 @@ public abstract class NamedParameterUtils {
|
||||
* @return the declared SqlParameter, or {@code null} if none found
|
||||
*/
|
||||
@Nullable
|
||||
private static SqlParameter findParameter(List<SqlParameter> declaredParams, String paramName, int paramIndex) {
|
||||
private static SqlParameter findParameter(
|
||||
@Nullable List<SqlParameter> declaredParams, String paramName, int paramIndex) {
|
||||
|
||||
if (declaredParams != null) {
|
||||
// First pass: Look for named parameter match.
|
||||
for (SqlParameter declaredParam : declaredParams) {
|
||||
@@ -420,7 +422,8 @@ public abstract class NamedParameterUtils {
|
||||
List<String> paramNames = parsedSql.getParameterNames();
|
||||
List<SqlParameter> params = new LinkedList<>();
|
||||
for (String paramName : paramNames) {
|
||||
params.add(new SqlParameter(paramName, paramSource.getSqlType(paramName), paramSource.getTypeName(paramName)));
|
||||
params.add(
|
||||
new SqlParameter(paramName, paramSource.getSqlType(paramName), paramSource.getTypeName(paramName)));
|
||||
}
|
||||
return params;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -63,6 +63,7 @@ public interface SqlParameterSource {
|
||||
* @return the value of the specified parameter
|
||||
* @throws IllegalArgumentException if there is no value for the requested parameter
|
||||
*/
|
||||
@Nullable
|
||||
Object getValue(String paramName) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,6 +20,7 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.jdbc.core.SqlParameterValue;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Class that provides helper methods for the use of {@link SqlParameterSource}
|
||||
@@ -66,6 +67,7 @@ public class SqlParameterSourceUtils {
|
||||
* @param parameterName the name of the parameter
|
||||
* @return the value object
|
||||
*/
|
||||
@Nullable
|
||||
public static Object getTypedValue(SqlParameterSource source, String parameterName) {
|
||||
int sqlType = source.getSqlType(parameterName);
|
||||
if (sqlType != SqlParameterSource.TYPE_UNKNOWN) {
|
||||
@@ -90,8 +92,7 @@ public class SqlParameterSourceUtils {
|
||||
Map<String, String> caseInsensitiveParameterNames = new HashMap<>();
|
||||
if (parameterSource instanceof BeanPropertySqlParameterSource) {
|
||||
String[] propertyNames = ((BeanPropertySqlParameterSource)parameterSource).getReadablePropertyNames();
|
||||
for (int i = 0; i < propertyNames.length; i++) {
|
||||
String name = propertyNames[i];
|
||||
for (String name : propertyNames) {
|
||||
caseInsensitiveParameterNames.put(name.toLowerCase(), name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.jdbc.core.metadata.CallMetaDataContext;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -114,6 +115,7 @@ public abstract class AbstractJdbcCall {
|
||||
/**
|
||||
* Get the name of the stored procedure.
|
||||
*/
|
||||
@Nullable
|
||||
public String getProcedureName() {
|
||||
return this.callMetaDataContext.getProcedureName();
|
||||
}
|
||||
@@ -142,6 +144,7 @@ public abstract class AbstractJdbcCall {
|
||||
/**
|
||||
* Get the catalog name used.
|
||||
*/
|
||||
@Nullable
|
||||
public String getCatalogName() {
|
||||
return this.callMetaDataContext.getCatalogName();
|
||||
}
|
||||
@@ -156,6 +159,7 @@ public abstract class AbstractJdbcCall {
|
||||
/**
|
||||
* Get the schema name used.
|
||||
*/
|
||||
@Nullable
|
||||
public String getSchemaName() {
|
||||
return this.callMetaDataContext.getSchemaName();
|
||||
}
|
||||
@@ -300,7 +304,9 @@ public abstract class AbstractJdbcCall {
|
||||
* Invoked after this base class's compilation is complete.
|
||||
*/
|
||||
protected void compileInternal() {
|
||||
this.callMetaDataContext.initializeMetaData(getJdbcTemplate().getDataSource());
|
||||
DataSource dataSource = getJdbcTemplate().getDataSource();
|
||||
Assert.state(dataSource != null, "No DataSource set");
|
||||
this.callMetaDataContext.initializeMetaData(dataSource);
|
||||
|
||||
// Iterate over the declared RowMappers and register the corresponding SqlParameter
|
||||
for (Map.Entry<String, RowMapper<?>> entry : this.declaredRowMappers.entrySet()) {
|
||||
@@ -409,6 +415,7 @@ public abstract class AbstractJdbcCall {
|
||||
* Get the name of a single out parameter or return value.
|
||||
* Used for functions or procedures with one out parameter.
|
||||
*/
|
||||
@Nullable
|
||||
protected String getScalarOutParameterName() {
|
||||
return this.callMetaDataContext.getScalarOutParameterName();
|
||||
}
|
||||
|
||||
@@ -32,14 +32,12 @@ import javax.sql.DataSource;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.dao.InvalidDataAccessResourceUsageException;
|
||||
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
|
||||
import org.springframework.jdbc.core.ConnectionCallback;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.PreparedStatementCreator;
|
||||
import org.springframework.jdbc.core.SqlTypeValue;
|
||||
import org.springframework.jdbc.core.StatementCreatorUtils;
|
||||
import org.springframework.jdbc.core.metadata.TableMetaDataContext;
|
||||
@@ -47,6 +45,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.support.GeneratedKeyHolder;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
import org.springframework.jdbc.support.KeyHolder;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -128,6 +127,7 @@ public abstract class AbstractJdbcInsert {
|
||||
/**
|
||||
* Get the name of the table for this insert.
|
||||
*/
|
||||
@Nullable
|
||||
public String getTableName() {
|
||||
return this.tableMetaDataContext.getTableName();
|
||||
}
|
||||
@@ -143,6 +143,7 @@ public abstract class AbstractJdbcInsert {
|
||||
/**
|
||||
* Get the name of the schema for this insert.
|
||||
*/
|
||||
@Nullable
|
||||
public String getSchemaName() {
|
||||
return this.tableMetaDataContext.getSchemaName();
|
||||
}
|
||||
@@ -158,6 +159,7 @@ public abstract class AbstractJdbcInsert {
|
||||
/**
|
||||
* Get the name of the catalog for this insert.
|
||||
*/
|
||||
@Nullable
|
||||
public String getCatalogName() {
|
||||
return this.tableMetaDataContext.getCatalogName();
|
||||
}
|
||||
@@ -268,8 +270,9 @@ public abstract class AbstractJdbcInsert {
|
||||
* Invoked after this base class's compilation is complete.
|
||||
*/
|
||||
protected void compileInternal() {
|
||||
this.tableMetaDataContext.processMetaData(
|
||||
getJdbcTemplate().getDataSource(), getColumnNames(), getGeneratedKeyNames());
|
||||
DataSource dataSource = getJdbcTemplate().getDataSource();
|
||||
Assert.state(dataSource != null, "No DataSource set");
|
||||
this.tableMetaDataContext.processMetaData(dataSource, getColumnNames(), getGeneratedKeyNames());
|
||||
this.insertString = this.tableMetaDataContext.createInsertString(getGeneratedKeyNames());
|
||||
this.insertTypes = this.tableMetaDataContext.createInsertTypes();
|
||||
if (logger.isDebugEnabled()) {
|
||||
@@ -406,7 +409,7 @@ public abstract class AbstractJdbcInsert {
|
||||
*/
|
||||
private Number executeInsertAndReturnKeyInternal(final List<?> values) {
|
||||
KeyHolder kh = executeInsertAndReturnKeyHolderInternal(values);
|
||||
if (kh != null && kh.getKey() != null) {
|
||||
if (kh.getKey() != null) {
|
||||
return kh.getKey();
|
||||
}
|
||||
else {
|
||||
@@ -423,18 +426,17 @@ public abstract class AbstractJdbcInsert {
|
||||
logger.debug("The following parameters are used for call " + getInsertString() + " with: " + values);
|
||||
}
|
||||
final KeyHolder keyHolder = new GeneratedKeyHolder();
|
||||
|
||||
if (this.tableMetaDataContext.isGetGeneratedKeysSupported()) {
|
||||
getJdbcTemplate().update(
|
||||
new PreparedStatementCreator() {
|
||||
@Override
|
||||
public PreparedStatement createPreparedStatement(Connection con) throws SQLException {
|
||||
PreparedStatement ps = prepareStatementForGeneratedKeys(con);
|
||||
setParameterValues(ps, values, getInsertTypes());
|
||||
return ps;
|
||||
}
|
||||
con -> {
|
||||
PreparedStatement ps = prepareStatementForGeneratedKeys(con);
|
||||
setParameterValues(ps, values, getInsertTypes());
|
||||
return ps;
|
||||
},
|
||||
keyHolder);
|
||||
}
|
||||
|
||||
else {
|
||||
if (!this.tableMetaDataContext.isGetGeneratedKeysSimulated()) {
|
||||
throw new InvalidDataAccessResourceUsageException(
|
||||
@@ -449,12 +451,16 @@ public abstract class AbstractJdbcInsert {
|
||||
"Current database only supports retrieving the key for a single column. There are " +
|
||||
getGeneratedKeyNames().length + " columns specified: " + Arrays.asList(getGeneratedKeyNames()));
|
||||
}
|
||||
|
||||
Assert.state(getTableName() != null, "No table name set");
|
||||
final String keyQuery = this.tableMetaDataContext.getSimulationQueryForGetGeneratedKey(
|
||||
getTableName(), getGeneratedKeyNames()[0]);
|
||||
Assert.state(keyQuery != null, "Query for simulating get generated keys can't be null");
|
||||
|
||||
// This is a hack to be able to get the generated key from a database that doesn't support
|
||||
// get generated keys feature. HSQL is one, PostgreSQL is another. Postgres uses a RETURNING
|
||||
// clause while HSQL uses a second query that has to be executed with the same connection.
|
||||
final String keyQuery = this.tableMetaDataContext.getSimulationQueryForGetGeneratedKey(
|
||||
this.tableMetaDataContext.getTableName(), getGeneratedKeyNames()[0]);
|
||||
Assert.notNull(keyQuery, "Query for simulating get generated keys can't be null");
|
||||
|
||||
if (keyQuery.toUpperCase().startsWith("RETURNING")) {
|
||||
Long key = getJdbcTemplate().queryForObject(getInsertString() + " " + keyQuery,
|
||||
values.toArray(new Object[values.size()]), Long.class);
|
||||
@@ -463,42 +469,39 @@ public abstract class AbstractJdbcInsert {
|
||||
keyHolder.getKeyList().add(keys);
|
||||
}
|
||||
else {
|
||||
getJdbcTemplate().execute(new ConnectionCallback<Object>() {
|
||||
@Override
|
||||
public Object doInConnection(Connection con) throws SQLException, DataAccessException {
|
||||
// Do the insert
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = con.prepareStatement(getInsertString());
|
||||
setParameterValues(ps, values, getInsertTypes());
|
||||
ps.executeUpdate();
|
||||
}
|
||||
finally {
|
||||
JdbcUtils.closeStatement(ps);
|
||||
}
|
||||
//Get the key
|
||||
Statement keyStmt = null;
|
||||
ResultSet rs = null;
|
||||
Map<String, Object> keys = new HashMap<>(1);
|
||||
try {
|
||||
keyStmt = con.createStatement();
|
||||
rs = keyStmt.executeQuery(keyQuery);
|
||||
if (rs.next()) {
|
||||
long key = rs.getLong(1);
|
||||
keys.put(getGeneratedKeyNames()[0], key);
|
||||
keyHolder.getKeyList().add(keys);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
JdbcUtils.closeResultSet(rs);
|
||||
JdbcUtils.closeStatement(keyStmt);
|
||||
}
|
||||
return null;
|
||||
getJdbcTemplate().execute((ConnectionCallback<Object>) con -> {
|
||||
// Do the insert
|
||||
PreparedStatement ps = null;
|
||||
try {
|
||||
ps = con.prepareStatement(getInsertString());
|
||||
setParameterValues(ps, values, getInsertTypes());
|
||||
ps.executeUpdate();
|
||||
}
|
||||
finally {
|
||||
JdbcUtils.closeStatement(ps);
|
||||
}
|
||||
//Get the key
|
||||
Statement keyStmt = null;
|
||||
ResultSet rs = null;
|
||||
Map<String, Object> keys = new HashMap<>(1);
|
||||
try {
|
||||
keyStmt = con.createStatement();
|
||||
rs = keyStmt.executeQuery(keyQuery);
|
||||
if (rs.next()) {
|
||||
long key = rs.getLong(1);
|
||||
keys.put(getGeneratedKeyNames()[0], key);
|
||||
keyHolder.getKeyList().add(keys);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
JdbcUtils.closeResultSet(rs);
|
||||
JdbcUtils.closeStatement(keyStmt);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
}
|
||||
return keyHolder;
|
||||
}
|
||||
|
||||
return keyHolder;
|
||||
}
|
||||
|
||||
@@ -582,7 +585,7 @@ public abstract class AbstractJdbcInsert {
|
||||
* @param preparedStatement the PreparedStatement
|
||||
* @param values the values to be set
|
||||
*/
|
||||
private void setParameterValues(PreparedStatement preparedStatement, List<?> values, int... columnTypes)
|
||||
private void setParameterValues(PreparedStatement preparedStatement, List<?> values, @Nullable int... columnTypes)
|
||||
throws SQLException {
|
||||
|
||||
int colIndex = 0;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -21,6 +21,7 @@ import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.springframework.jdbc.core.SqlTypeValue;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Abstract implementation of the SqlTypeValue interface, for convenient
|
||||
@@ -53,7 +54,7 @@ import org.springframework.jdbc.core.SqlTypeValue;
|
||||
public abstract class AbstractSqlTypeValue implements SqlTypeValue {
|
||||
|
||||
@Override
|
||||
public final void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName)
|
||||
public final void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, @Nullable String typeName)
|
||||
throws SQLException {
|
||||
|
||||
Object value = createTypeValue(ps.getConnection(), sqlType, typeName);
|
||||
@@ -75,6 +76,7 @@ public abstract class AbstractSqlTypeValue implements SqlTypeValue {
|
||||
* parameter values (that is, there's no need to catch SQLException)
|
||||
* @see java.sql.PreparedStatement#setObject(int, Object, int)
|
||||
*/
|
||||
protected abstract Object createTypeValue(Connection con, int sqlType, String typeName) throws SQLException;
|
||||
protected abstract Object createTypeValue(Connection con, int sqlType, @Nullable String typeName)
|
||||
throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -24,6 +24,7 @@ import org.springframework.jdbc.CannotGetJdbcConnectionException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.DataSourceUtils;
|
||||
import org.springframework.jdbc.support.SQLExceptionTranslator;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Convenient super class for JDBC-based data access objects.
|
||||
@@ -129,7 +130,9 @@ public abstract class JdbcDaoSupport extends DaoSupport {
|
||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#getConnection(javax.sql.DataSource)
|
||||
*/
|
||||
protected final Connection getConnection() throws CannotGetJdbcConnectionException {
|
||||
return DataSourceUtils.getConnection(getDataSource());
|
||||
DataSource dataSource = getDataSource();
|
||||
Assert.state(dataSource != null, "No DataSource set");
|
||||
return DataSourceUtils.getConnection(dataSource);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@ import org.springframework.jdbc.core.DisposableSqlTypeValue;
|
||||
import org.springframework.jdbc.support.lob.DefaultLobHandler;
|
||||
import org.springframework.jdbc.support.lob.LobCreator;
|
||||
import org.springframework.jdbc.support.lob.LobHandler;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Object to represent an SQL BLOB/CLOB value parameter. BLOBs can either be an
|
||||
@@ -82,7 +83,7 @@ public class SqlLobValue implements DisposableSqlTypeValue {
|
||||
* @param bytes the byte array containing the BLOB value
|
||||
* @see org.springframework.jdbc.support.lob.DefaultLobHandler
|
||||
*/
|
||||
public SqlLobValue(byte[] bytes) {
|
||||
public SqlLobValue(@Nullable byte[] bytes) {
|
||||
this(bytes, new DefaultLobHandler());
|
||||
}
|
||||
|
||||
@@ -91,7 +92,7 @@ public class SqlLobValue implements DisposableSqlTypeValue {
|
||||
* @param bytes the byte array containing the BLOB value
|
||||
* @param lobHandler the LobHandler to be used
|
||||
*/
|
||||
public SqlLobValue(byte[] bytes, LobHandler lobHandler) {
|
||||
public SqlLobValue(@Nullable byte[] bytes, LobHandler lobHandler) {
|
||||
this.content = bytes;
|
||||
this.length = (bytes != null ? bytes.length : 0);
|
||||
this.lobCreator = lobHandler.getLobCreator();
|
||||
@@ -103,7 +104,7 @@ public class SqlLobValue implements DisposableSqlTypeValue {
|
||||
* @param content the String containing the CLOB value
|
||||
* @see org.springframework.jdbc.support.lob.DefaultLobHandler
|
||||
*/
|
||||
public SqlLobValue(String content) {
|
||||
public SqlLobValue(@Nullable String content) {
|
||||
this(content, new DefaultLobHandler());
|
||||
}
|
||||
|
||||
@@ -112,7 +113,7 @@ public class SqlLobValue implements DisposableSqlTypeValue {
|
||||
* @param content the String containing the CLOB value
|
||||
* @param lobHandler the LobHandler to be used
|
||||
*/
|
||||
public SqlLobValue(String content, LobHandler lobHandler) {
|
||||
public SqlLobValue(@Nullable String content, LobHandler lobHandler) {
|
||||
this.content = content;
|
||||
this.length = (content != null ? content.length() : 0);
|
||||
this.lobCreator = lobHandler.getLobCreator();
|
||||
@@ -169,7 +170,9 @@ public class SqlLobValue implements DisposableSqlTypeValue {
|
||||
* Set the specified content via the LobCreator.
|
||||
*/
|
||||
@Override
|
||||
public void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, String typeName) throws SQLException {
|
||||
public void setTypeValue(PreparedStatement ps, int paramIndex, int sqlType, @Nullable String typeName)
|
||||
throws SQLException {
|
||||
|
||||
if (sqlType == Types.BLOB) {
|
||||
if (this.content instanceof byte[] || this.content == null) {
|
||||
this.lobCreator.setBlobAsBytes(ps, paramIndex, (byte[]) this.content);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -59,6 +59,7 @@ public abstract class AbstractDriverBasedDataSource extends AbstractDataSource {
|
||||
/**
|
||||
* Return the JDBC URL to use for connecting through the Driver.
|
||||
*/
|
||||
@Nullable
|
||||
public String getUrl() {
|
||||
return this.url;
|
||||
}
|
||||
@@ -74,6 +75,7 @@ public abstract class AbstractDriverBasedDataSource extends AbstractDataSource {
|
||||
/**
|
||||
* Return the JDBC username to use for connecting through the Driver.
|
||||
*/
|
||||
@Nullable
|
||||
public String getUsername() {
|
||||
return this.username;
|
||||
}
|
||||
@@ -89,6 +91,7 @@ public abstract class AbstractDriverBasedDataSource extends AbstractDataSource {
|
||||
/**
|
||||
* Return the JDBC password to use for connecting through the Driver.
|
||||
*/
|
||||
@Nullable
|
||||
public String getPassword() {
|
||||
return this.password;
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import org.springframework.transaction.support.DefaultTransactionStatus;
|
||||
import org.springframework.transaction.support.ResourceTransactionManager;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationUtils;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* {@link org.springframework.transaction.PlatformTransactionManager}
|
||||
@@ -168,10 +169,23 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
|
||||
/**
|
||||
* Return the JDBC DataSource that this instance manages transactions for.
|
||||
*/
|
||||
@Nullable
|
||||
public DataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the DataSource for actual use.
|
||||
* @return the DataSource (never {@code null})
|
||||
* @throws IllegalStateException in case of no DataSource set
|
||||
* @since 5.0
|
||||
*/
|
||||
protected DataSource obtainDataSource() {
|
||||
DataSource dataSource = getDataSource();
|
||||
Assert.state(dataSource != null, "No DataSource set");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify whether to enforce the read-only nature of a transaction
|
||||
* (as indicated by {@link TransactionDefinition#isReadOnly()}
|
||||
@@ -214,7 +228,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
|
||||
|
||||
@Override
|
||||
public Object getResourceFactory() {
|
||||
return getDataSource();
|
||||
return obtainDataSource();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -230,7 +244,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
|
||||
@Override
|
||||
protected boolean isExistingTransaction(Object transaction) {
|
||||
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
|
||||
return (txObject.getConnectionHolder() != null && txObject.getConnectionHolder().isTransactionActive());
|
||||
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,9 +256,9 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
|
||||
Connection con = null;
|
||||
|
||||
try {
|
||||
if (txObject.getConnectionHolder() == null ||
|
||||
if (!txObject.hasConnectionHolder() ||
|
||||
txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
|
||||
Connection newCon = this.dataSource.getConnection();
|
||||
Connection newCon = obtainDataSource().getConnection();
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Acquired Connection [" + newCon + "] for JDBC transaction");
|
||||
}
|
||||
@@ -278,7 +292,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
|
||||
|
||||
// Bind the connection holder to the thread.
|
||||
if (txObject.isNewConnectionHolder()) {
|
||||
TransactionSynchronizationManager.bindResource(getDataSource(), txObject.getConnectionHolder());
|
||||
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -299,7 +313,7 @@ public class DataSourceTransactionManager extends AbstractPlatformTransactionMan
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doResume(Object transaction, Object suspendedResources) {
|
||||
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
|
||||
TransactionSynchronizationManager.bindResource(this.dataSource, suspendedResources);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package org.springframework.jdbc.datasource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -144,7 +143,7 @@ public abstract class DataSourceUtils {
|
||||
* @see #resetConnectionAfterTransaction
|
||||
*/
|
||||
@Nullable
|
||||
public static Integer prepareConnectionForTransaction(Connection con, TransactionDefinition definition)
|
||||
public static Integer prepareConnectionForTransaction(Connection con, @Nullable TransactionDefinition definition)
|
||||
throws SQLException {
|
||||
|
||||
Assert.notNull(con, "No Connection specified");
|
||||
@@ -244,7 +243,7 @@ public abstract class DataSourceUtils {
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @see java.sql.Statement#setQueryTimeout
|
||||
*/
|
||||
public static void applyTransactionTimeout(Statement stmt, DataSource dataSource) throws SQLException {
|
||||
public static void applyTransactionTimeout(Statement stmt, @Nullable DataSource dataSource) throws SQLException {
|
||||
applyTimeout(stmt, dataSource, -1);
|
||||
}
|
||||
|
||||
@@ -257,10 +256,12 @@ public abstract class DataSourceUtils {
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @see java.sql.Statement#setQueryTimeout
|
||||
*/
|
||||
public static void applyTimeout(Statement stmt, DataSource dataSource, int timeout) throws SQLException {
|
||||
public static void applyTimeout(Statement stmt, @Nullable DataSource dataSource, int timeout) throws SQLException {
|
||||
Assert.notNull(stmt, "No Statement specified");
|
||||
Assert.notNull(dataSource, "No DataSource specified");
|
||||
ConnectionHolder holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
|
||||
ConnectionHolder holder = null;
|
||||
if (dataSource != null) {
|
||||
holder = (ConnectionHolder) TransactionSynchronizationManager.getResource(dataSource);
|
||||
}
|
||||
if (holder != null && holder.hasTimeout()) {
|
||||
// Remaining transaction timeout overrides specified value.
|
||||
stmt.setQueryTimeout(holder.getTimeToLiveInSeconds());
|
||||
@@ -280,7 +281,7 @@ public abstract class DataSourceUtils {
|
||||
* (may be {@code null})
|
||||
* @see #getConnection
|
||||
*/
|
||||
public static void releaseConnection(Connection con, @Nullable DataSource dataSource) {
|
||||
public static void releaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) {
|
||||
try {
|
||||
doReleaseConnection(con, dataSource);
|
||||
}
|
||||
@@ -303,7 +304,7 @@ public abstract class DataSourceUtils {
|
||||
* @throws SQLException if thrown by JDBC methods
|
||||
* @see #doGetConnection
|
||||
*/
|
||||
public static void doReleaseConnection(Connection con, @Nullable DataSource dataSource) throws SQLException {
|
||||
public static void doReleaseConnection(@Nullable Connection con, @Nullable DataSource dataSource) throws SQLException {
|
||||
if (con == null) {
|
||||
return;
|
||||
}
|
||||
@@ -327,7 +328,7 @@ public abstract class DataSourceUtils {
|
||||
* @see Connection#close()
|
||||
* @see SmartDataSource#shouldClose(Connection)
|
||||
*/
|
||||
public static void doCloseConnection(Connection con, DataSource dataSource) throws SQLException {
|
||||
public static void doCloseConnection(Connection con, @Nullable DataSource dataSource) throws SQLException {
|
||||
if (!(dataSource instanceof SmartDataSource) || ((SmartDataSource) dataSource).shouldClose(con)) {
|
||||
con.close();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -23,6 +23,7 @@ import java.util.logging.Logger;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -69,10 +70,21 @@ public class DelegatingDataSource implements DataSource, InitializingBean {
|
||||
/**
|
||||
* Return the target DataSource that this DataSource should delegate to.
|
||||
*/
|
||||
@Nullable
|
||||
public DataSource getTargetDataSource() {
|
||||
return this.targetDataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the target {@code DataSource} for actual use (never {@code null}).
|
||||
* @since 5.0
|
||||
*/
|
||||
protected DataSource obtainTargetDataSource() {
|
||||
DataSource dataSource = getTargetDataSource();
|
||||
Assert.state(dataSource != null, "No 'targetDataSource' set");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() {
|
||||
if (getTargetDataSource() == null) {
|
||||
@@ -83,32 +95,32 @@ public class DelegatingDataSource implements DataSource, InitializingBean {
|
||||
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
return getTargetDataSource().getConnection();
|
||||
return obtainTargetDataSource().getConnection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Connection getConnection(String username, String password) throws SQLException {
|
||||
return getTargetDataSource().getConnection(username, password);
|
||||
return obtainTargetDataSource().getConnection(username, password);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PrintWriter getLogWriter() throws SQLException {
|
||||
return getTargetDataSource().getLogWriter();
|
||||
return obtainTargetDataSource().getLogWriter();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogWriter(PrintWriter out) throws SQLException {
|
||||
getTargetDataSource().setLogWriter(out);
|
||||
obtainTargetDataSource().setLogWriter(out);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLoginTimeout() throws SQLException {
|
||||
return getTargetDataSource().getLoginTimeout();
|
||||
return obtainTargetDataSource().getLoginTimeout();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLoginTimeout(int seconds) throws SQLException {
|
||||
getTargetDataSource().setLoginTimeout(seconds);
|
||||
obtainTargetDataSource().setLoginTimeout(seconds);
|
||||
}
|
||||
|
||||
|
||||
@@ -122,12 +134,12 @@ public class DelegatingDataSource implements DataSource, InitializingBean {
|
||||
if (iface.isInstance(this)) {
|
||||
return (T) this;
|
||||
}
|
||||
return getTargetDataSource().unwrap(iface);
|
||||
return obtainTargetDataSource().unwrap(iface);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||
return (iface.isInstance(this) || getTargetDataSource().isWrapperFor(iface));
|
||||
return (iface.isInstance(this) || obtainTargetDataSource().isWrapperFor(iface));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -138,6 +138,7 @@ public class DriverManagerDataSource extends AbstractDriverBasedDataSource {
|
||||
@Override
|
||||
protected Connection getConnectionFromDriver(Properties props) throws SQLException {
|
||||
String url = getUrl();
|
||||
Assert.state(url != null, "'url' not set");
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Creating new JDBC DriverManager Connection to [" + url + "]");
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -76,7 +76,7 @@ public class IsolationLevelDataSourceAdapter extends UserCredentialsDataSourceAd
|
||||
* @see #setIsolationLevel
|
||||
*/
|
||||
public final void setIsolationLevelName(String constantName) throws IllegalArgumentException {
|
||||
if (constantName == null || !constantName.startsWith(DefaultTransactionDefinition.PREFIX_ISOLATION)) {
|
||||
if (!constantName.startsWith(DefaultTransactionDefinition.PREFIX_ISOLATION)) {
|
||||
throw new IllegalArgumentException("Only isolation constants allowed");
|
||||
}
|
||||
setIsolationLevel(constants.asNumber(constantName).intValue());
|
||||
@@ -160,6 +160,7 @@ public class IsolationLevelDataSourceAdapter extends UserCredentialsDataSourceAd
|
||||
* @return whether there is a read-only hint for the current scope
|
||||
* @see org.springframework.transaction.support.TransactionSynchronizationManager#isCurrentTransactionReadOnly()
|
||||
*/
|
||||
@Nullable
|
||||
protected Boolean getCurrentReadOnlyFlag() {
|
||||
boolean txReadOnly = TransactionSynchronizationManager.isCurrentTransactionReadOnly();
|
||||
return (txReadOnly ? Boolean.TRUE : null);
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionSystemException;
|
||||
import org.springframework.transaction.TransactionUsageException;
|
||||
import org.springframework.transaction.support.SmartTransactionObject;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Convenient base class for JDBC-aware transaction objects. Can contain a
|
||||
@@ -62,6 +63,7 @@ public abstract class JdbcTransactionObjectSupport implements SavepointManager,
|
||||
}
|
||||
|
||||
public ConnectionHolder getConnectionHolder() {
|
||||
Assert.state(this.connectionHolder != null, "No ConnectionHolder available");
|
||||
return this.connectionHolder;
|
||||
}
|
||||
|
||||
@@ -69,7 +71,7 @@ public abstract class JdbcTransactionObjectSupport implements SavepointManager,
|
||||
return (this.connectionHolder != null);
|
||||
}
|
||||
|
||||
public void setPreviousIsolationLevel(Integer previousIsolationLevel) {
|
||||
public void setPreviousIsolationLevel(@Nullable Integer previousIsolationLevel) {
|
||||
this.previousIsolationLevel = previousIsolationLevel;
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ public class LazyConnectionDataSourceProxy extends DelegatingDataSource {
|
||||
// via a Connection from the target DataSource, if possible.
|
||||
if (this.defaultAutoCommit == null || this.defaultTransactionIsolation == null) {
|
||||
try {
|
||||
Connection con = getTargetDataSource().getConnection();
|
||||
Connection con = obtainTargetDataSource().getConnection();
|
||||
try {
|
||||
checkDefaultConnectionProperties(con);
|
||||
}
|
||||
@@ -398,8 +398,8 @@ public class LazyConnectionDataSourceProxy extends DelegatingDataSource {
|
||||
|
||||
// Fetch physical Connection from DataSource.
|
||||
this.target = (this.username != null) ?
|
||||
getTargetDataSource().getConnection(this.username, this.password) :
|
||||
getTargetDataSource().getConnection();
|
||||
obtainTargetDataSource().getConnection(this.username, this.password) :
|
||||
obtainTargetDataSource().getConnection();
|
||||
|
||||
// If we still lack default connection properties, check them now.
|
||||
checkDefaultConnectionProperties(this.target);
|
||||
@@ -407,7 +407,7 @@ public class LazyConnectionDataSourceProxy extends DelegatingDataSource {
|
||||
// Apply kept transaction settings, if any.
|
||||
if (this.readOnly) {
|
||||
try {
|
||||
this.target.setReadOnly(this.readOnly);
|
||||
this.target.setReadOnly(true);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// "read-only not supported" -> ignore, it's just a hint anyway
|
||||
|
||||
@@ -292,6 +292,7 @@ public class SingleConnectionDataSource extends DriverManagerDataSource implemen
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
|
||||
// Invocation on ConnectionProxy interface coming in...
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Proxy for a target JDBC {@link javax.sql.DataSource}, adding awareness of
|
||||
@@ -119,9 +118,7 @@ public class TransactionAwareDataSourceProxy extends DelegatingDataSource {
|
||||
*/
|
||||
@Override
|
||||
public Connection getConnection() throws SQLException {
|
||||
DataSource ds = getTargetDataSource();
|
||||
Assert.state(ds != null, "'targetDataSource' is required");
|
||||
return getTransactionAwareConnectionProxy(ds);
|
||||
return getTransactionAwareConnectionProxy(obtainTargetDataSource());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,13 +19,13 @@ package org.springframework.jdbc.datasource;
|
||||
import java.lang.reflect.Method;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -141,8 +141,10 @@ public class WebSphereDataSourceAdapter extends IsolationLevelDataSourceAdapter
|
||||
getTargetDataSource() + "], using ConnectionSpec [" + connSpec + "]");
|
||||
}
|
||||
// Create Connection through invoking WSDataSource.getConnection(JDBCConnectionSpec)
|
||||
return (Connection) ReflectionUtils.invokeJdbcMethod(
|
||||
this.wsDataSourceGetConnectionMethod, getTargetDataSource(), connSpec);
|
||||
Connection con = (Connection) ReflectionUtils.invokeJdbcMethod(
|
||||
this.wsDataSourceGetConnectionMethod, obtainTargetDataSource(), connSpec);
|
||||
Assert.state(con != null, "No Connection");
|
||||
return con;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -158,10 +160,11 @@ public class WebSphereDataSourceAdapter extends IsolationLevelDataSourceAdapter
|
||||
* @throws SQLException if thrown by JDBCConnectionSpec API methods
|
||||
* @see com.ibm.websphere.rsadapter.JDBCConnectionSpec
|
||||
*/
|
||||
protected Object createConnectionSpec(
|
||||
@Nullable Integer isolationLevel, @Nullable Boolean readOnlyFlag, @Nullable String username, @Nullable String password) throws SQLException {
|
||||
protected Object createConnectionSpec(@Nullable Integer isolationLevel, @Nullable Boolean readOnlyFlag,
|
||||
@Nullable String username, @Nullable String password) throws SQLException {
|
||||
|
||||
Object connSpec = ReflectionUtils.invokeJdbcMethod(this.newJdbcConnSpecMethod, null);
|
||||
Assert.state(connSpec != null, "No JDBCConnectionSpec");
|
||||
if (isolationLevel != null) {
|
||||
ReflectionUtils.invokeJdbcMethod(this.setTransactionIsolationMethod, connSpec, isolationLevel);
|
||||
}
|
||||
|
||||
@@ -213,7 +213,6 @@ public class EmbeddedDatabaseFactory {
|
||||
*/
|
||||
protected void shutdownDatabase() {
|
||||
if (this.dataSource != null) {
|
||||
|
||||
if (logger.isInfoEnabled()) {
|
||||
if (this.dataSource instanceof SimpleDriverDataSource) {
|
||||
logger.info(String.format("Shutting down embedded database: url='%s'",
|
||||
@@ -223,7 +222,6 @@ public class EmbeddedDatabaseFactory {
|
||||
logger.info(String.format("Shutting down embedded database '%s'", this.databaseName));
|
||||
}
|
||||
}
|
||||
|
||||
this.databaseConfigurer.shutdown(this.dataSource, this.databaseName);
|
||||
this.dataSource = null;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -81,7 +81,7 @@ public class EmbeddedDatabaseFactoryBean extends EmbeddedDatabaseFactory
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
if (this.databaseCleaner != null) {
|
||||
if (this.databaseCleaner != null && getDataSource() != null) {
|
||||
DatabasePopulatorUtils.execute(this.databaseCleaner, getDataSource());
|
||||
}
|
||||
shutdownDatabase();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,6 +20,7 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -54,10 +55,8 @@ public class DataSourceInitializer implements InitializingBean, DisposableBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the {@link DatabasePopulator} to execute during the bean initialization
|
||||
* phase.
|
||||
* @param databasePopulator the {@code DatabasePopulator} to use during
|
||||
* initialization
|
||||
* Set the {@link DatabasePopulator} to execute during the bean initialization phase.
|
||||
* @param databasePopulator the {@code DatabasePopulator} to use during initialization
|
||||
* @see #setDatabaseCleaner
|
||||
*/
|
||||
public void setDatabasePopulator(DatabasePopulator databasePopulator) {
|
||||
@@ -84,6 +83,7 @@ public class DataSourceInitializer implements InitializingBean, DisposableBean {
|
||||
this.enabled = enabled;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Use the {@linkplain #setDatabasePopulator database populator} to set up
|
||||
* the database.
|
||||
@@ -102,8 +102,8 @@ public class DataSourceInitializer implements InitializingBean, DisposableBean {
|
||||
execute(this.databaseCleaner);
|
||||
}
|
||||
|
||||
private void execute(DatabasePopulator populator) {
|
||||
Assert.state(dataSource != null, "DataSource must be set");
|
||||
private void execute(@Nullable DatabasePopulator populator) {
|
||||
Assert.state(this.dataSource != null, "DataSource must be set");
|
||||
if (this.enabled && populator != null) {
|
||||
DatabasePopulatorUtils.execute(populator, this.dataSource);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -48,9 +48,7 @@ public abstract class DatabasePopulatorUtils {
|
||||
populator.populate(connection);
|
||||
}
|
||||
finally {
|
||||
if (connection != null) {
|
||||
DataSourceUtils.releaseConnection(connection, dataSource);
|
||||
}
|
||||
DataSourceUtils.releaseConnection(connection, dataSource);
|
||||
}
|
||||
}
|
||||
catch (Throwable ex) {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.jdbc.datasource.init;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Root of the hierarchy of data access exceptions that are related to processing
|
||||
@@ -41,7 +42,7 @@ public abstract class ScriptException extends DataAccessException {
|
||||
* @param message the detail message
|
||||
* @param cause the root cause
|
||||
*/
|
||||
public ScriptException(String message, Throwable cause) {
|
||||
public ScriptException(String message, @Nullable Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.jdbc.datasource.init;
|
||||
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Thrown by {@link ScriptUtils} if an SQL script cannot be properly parsed.
|
||||
@@ -32,7 +33,7 @@ public class ScriptParseException extends ScriptException {
|
||||
* @param message detailed message
|
||||
* @param resource the resource from which the SQL script was read
|
||||
*/
|
||||
public ScriptParseException(String message, EncodedResource resource) {
|
||||
public ScriptParseException(String message, @Nullable EncodedResource resource) {
|
||||
super(buildMessage(message, resource));
|
||||
}
|
||||
|
||||
@@ -42,13 +43,14 @@ public class ScriptParseException extends ScriptException {
|
||||
* @param resource the resource from which the SQL script was read
|
||||
* @param cause the underlying cause of the failure
|
||||
*/
|
||||
public ScriptParseException(String message, EncodedResource resource, Throwable cause) {
|
||||
public ScriptParseException(String message, @Nullable EncodedResource resource, @Nullable Throwable cause) {
|
||||
super(buildMessage(message, resource), cause);
|
||||
}
|
||||
|
||||
private static String buildMessage(String message, EncodedResource resource) {
|
||||
return String.format("Failed to parse SQL script from resource [%s]: %s", (resource == null ? "<unknown>"
|
||||
: resource), message);
|
||||
|
||||
private static String buildMessage(String message, @Nullable EncodedResource resource) {
|
||||
return String.format("Failed to parse SQL script from resource [%s]: %s",
|
||||
(resource == null ? "<unknown>" : resource), message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -274,8 +274,8 @@ public abstract class ScriptUtils {
|
||||
* @return a {@code String} containing the script lines
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
private static String readScript(EncodedResource resource, String commentPrefix, String separator)
|
||||
throws IOException {
|
||||
private static String readScript(EncodedResource resource, @Nullable String commentPrefix,
|
||||
@Nullable String separator) throws IOException {
|
||||
|
||||
LineNumberReader lnr = new LineNumberReader(resource.getReader());
|
||||
try {
|
||||
@@ -301,8 +301,8 @@ public abstract class ScriptUtils {
|
||||
* @return a {@code String} containing the script lines
|
||||
* @throws IOException in case of I/O errors
|
||||
*/
|
||||
public static String readScript(LineNumberReader lineNumberReader, String commentPrefix, String separator)
|
||||
throws IOException {
|
||||
public static String readScript(LineNumberReader lineNumberReader, @Nullable String commentPrefix,
|
||||
@Nullable String separator) throws IOException {
|
||||
|
||||
String currentStatement = lineNumberReader.readLine();
|
||||
StringBuilder scriptBuilder = new StringBuilder();
|
||||
@@ -319,7 +319,7 @@ public abstract class ScriptUtils {
|
||||
return scriptBuilder.toString();
|
||||
}
|
||||
|
||||
private static void appendSeparatorToScriptIfNecessary(StringBuilder scriptBuilder, String separator) {
|
||||
private static void appendSeparatorToScriptIfNecessary(StringBuilder scriptBuilder, @Nullable String separator) {
|
||||
if (separator == null) {
|
||||
return;
|
||||
}
|
||||
@@ -434,8 +434,8 @@ public abstract class ScriptUtils {
|
||||
* @see org.springframework.jdbc.datasource.DataSourceUtils#releaseConnection
|
||||
*/
|
||||
public static void executeSqlScript(Connection connection, EncodedResource resource, boolean continueOnError,
|
||||
boolean ignoreFailedDrops, String commentPrefix, String separator, String blockCommentStartDelimiter,
|
||||
String blockCommentEndDelimiter) throws ScriptException {
|
||||
boolean ignoreFailedDrops, String commentPrefix, @Nullable String separator,
|
||||
String blockCommentStartDelimiter, String blockCommentEndDelimiter) throws ScriptException {
|
||||
|
||||
try {
|
||||
if (logger.isInfoEnabled()) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -24,6 +24,7 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.jdbc.datasource.AbstractDataSource;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -102,7 +103,7 @@ public abstract class AbstractRoutingDataSource extends AbstractDataSource imple
|
||||
* <p>Default is a {@link JndiDataSourceLookup}, allowing the JNDI names
|
||||
* of application server DataSources to be specified directly.
|
||||
*/
|
||||
public void setDataSourceLookup(DataSourceLookup dataSourceLookup) {
|
||||
public void setDataSourceLookup(@Nullable DataSourceLookup dataSourceLookup) {
|
||||
this.dataSourceLookup = (dataSourceLookup != null ? dataSourceLookup : new JndiDataSourceLookup());
|
||||
}
|
||||
|
||||
@@ -211,6 +212,7 @@ public abstract class AbstractRoutingDataSource extends AbstractDataSource imple
|
||||
* to match the stored lookup key type, as resolved by the
|
||||
* {@link #resolveSpecifiedLookupKey} method.
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract Object determineCurrentLookupKey();
|
||||
|
||||
}
|
||||
|
||||
@@ -182,7 +182,7 @@ public class BatchSqlUpdate extends SqlUpdate {
|
||||
}
|
||||
|
||||
int[] rowsAffected = getJdbcTemplate().batchUpdate(
|
||||
getSql(),
|
||||
resolveSql(),
|
||||
new BatchPreparedStatementSetter() {
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -68,7 +68,7 @@ public class GenericSqlQuery<T> extends SqlQuery<T> {
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
protected RowMapper<T> newRowMapper(@Nullable Object[] parameters, Map<?, ?> context) {
|
||||
protected RowMapper<T> newRowMapper(@Nullable Object[] parameters, @Nullable Map<?, ?> context) {
|
||||
return (this.rowMapper != null ? this.rowMapper : BeanUtils.instantiateClass(this.rowMapperClass));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2008 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -80,6 +80,7 @@ public abstract class MappingSqlQuery<T> extends MappingSqlQueryWithParameters<T
|
||||
* Subclasses can simply not catch SQLExceptions, relying on the
|
||||
* framework to clean up.
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract T mapRow(ResultSet rs, int rowNum) throws SQLException;
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -72,7 +72,7 @@ public abstract class MappingSqlQueryWithParameters<T> extends SqlQuery<T> {
|
||||
* implementation of the mapRow() method.
|
||||
*/
|
||||
@Override
|
||||
protected RowMapper<T> newRowMapper(@Nullable Object[] parameters, Map<?, ?> context) {
|
||||
protected RowMapper<T> newRowMapper(@Nullable Object[] parameters, @Nullable Map<?, ?> context) {
|
||||
return new RowMapperImpl(parameters, context);
|
||||
}
|
||||
|
||||
@@ -91,6 +91,7 @@ public abstract class MappingSqlQueryWithParameters<T> extends SqlQuery<T> {
|
||||
* Subclasses can simply not catch SQLExceptions, relying on the
|
||||
* framework to clean up.
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract T mapRow(ResultSet rs, int rowNum, @Nullable Object[] parameters, @Nullable Map<?, ?> context)
|
||||
throws SQLException;
|
||||
|
||||
@@ -108,7 +109,7 @@ public abstract class MappingSqlQueryWithParameters<T> extends SqlQuery<T> {
|
||||
/**
|
||||
* Use an array results. More efficient if we know how many results to expect.
|
||||
*/
|
||||
public RowMapperImpl(Object[] parameters, Map<?, ?> context) {
|
||||
public RowMapperImpl(@Nullable Object[] parameters, @Nullable Map<?, ?> context) {
|
||||
this.params = parameters;
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -23,7 +23,6 @@ import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -34,6 +33,7 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An "RDBMS operation" is a multi-threaded, reusable object representing a query,
|
||||
@@ -93,9 +93,6 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
* apply to multiple RdbmsOperation objects.
|
||||
*/
|
||||
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
|
||||
if (jdbcTemplate == null) {
|
||||
throw new IllegalArgumentException("jdbcTemplate must not be null");
|
||||
}
|
||||
this.jdbcTemplate = jdbcTemplate;
|
||||
}
|
||||
|
||||
@@ -223,6 +220,7 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
/**
|
||||
* Return the column names of the auto generated keys.
|
||||
*/
|
||||
@Nullable
|
||||
public String[] getGeneratedKeysColumnNames() {
|
||||
return this.generatedKeysColumnNames;
|
||||
}
|
||||
@@ -235,14 +233,25 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses can override this to supply dynamic SQL if they wish,
|
||||
* but SQL is normally set by calling the setSql() method
|
||||
* or in a subclass constructor.
|
||||
* Subclasses can override this to supply dynamic SQL if they wish, but SQL is
|
||||
* normally set by calling the {@link #setSql} method or in a subclass constructor.
|
||||
*/
|
||||
@Nullable
|
||||
public String getSql() {
|
||||
return this.sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve the configured SQL for actual use.
|
||||
* @return the SQL (never {@code null})
|
||||
* @since 5.0
|
||||
*/
|
||||
protected String resolveSql() {
|
||||
String sql = getSql();
|
||||
Assert.state(sql != null, "No SQL set");
|
||||
return sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add anonymous parameters, specifying only their SQL types
|
||||
* as defined in the {@code java.sql.Types} class.
|
||||
@@ -252,7 +261,7 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
* {@code java.sql.Types} class
|
||||
* @throws InvalidDataAccessApiUsageException if the operation is already compiled
|
||||
*/
|
||||
public void setTypes(int[] types) throws InvalidDataAccessApiUsageException {
|
||||
public void setTypes(@Nullable int[] types) throws InvalidDataAccessApiUsageException {
|
||||
if (isCompiled()) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot add parameters once query is compiled");
|
||||
}
|
||||
@@ -289,7 +298,7 @@ public abstract class RdbmsOperation implements InitializingBean {
|
||||
* @param parameters Array containing the declared {@link SqlParameter} objects
|
||||
* @see #declaredParameters
|
||||
*/
|
||||
public void setParameters(SqlParameter[] parameters) {
|
||||
public void setParameters(SqlParameter... parameters) {
|
||||
if (isCompiled()) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot add parameters once the query is compiled");
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.TypeMismatchDataAccessException;
|
||||
import org.springframework.jdbc.core.SingleColumnRowMapper;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* SQL "function" wrapper for a query that returns a single row of results.
|
||||
@@ -168,8 +169,9 @@ public class SqlFunction<T> extends MappingSqlQuery<T> {
|
||||
* returning the value as an object.
|
||||
* @return the value of the function
|
||||
*/
|
||||
@Nullable
|
||||
public Object runGeneric() {
|
||||
return findObject((Object[]) null);
|
||||
return findObject((Object[]) null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,6 +179,7 @@ public class SqlFunction<T> extends MappingSqlQuery<T> {
|
||||
* @param parameter single int parameter
|
||||
* @return the value of the function as an Object
|
||||
*/
|
||||
@Nullable
|
||||
public Object runGeneric(int parameter) {
|
||||
return findObject(parameter);
|
||||
}
|
||||
@@ -189,6 +192,7 @@ public class SqlFunction<T> extends MappingSqlQuery<T> {
|
||||
* @return the value of the function, as an Object
|
||||
* @see #execute(Object[])
|
||||
*/
|
||||
@Nullable
|
||||
public Object runGeneric(Object[] parameters) {
|
||||
return findObject(parameters);
|
||||
}
|
||||
|
||||
@@ -54,7 +54,7 @@ public abstract class SqlOperation extends RdbmsOperation {
|
||||
*/
|
||||
@Override
|
||||
protected final void compileInternal() {
|
||||
this.preparedStatementFactory = new PreparedStatementCreatorFactory(getSql(), getDeclaredParameters());
|
||||
this.preparedStatementFactory = new PreparedStatementCreatorFactory(resolveSql(), getDeclaredParameters());
|
||||
this.preparedStatementFactory.setResultSetType(getResultSetType());
|
||||
this.preparedStatementFactory.setUpdatableResults(isUpdatableResults());
|
||||
this.preparedStatementFactory.setReturnGeneratedKeys(isReturnGeneratedKeys());
|
||||
@@ -80,7 +80,7 @@ public abstract class SqlOperation extends RdbmsOperation {
|
||||
protected ParsedSql getParsedSql() {
|
||||
synchronized (this.parsedSqlMonitor) {
|
||||
if (this.cachedSql == null) {
|
||||
this.cachedSql = NamedParameterUtils.parseSqlStatement(getSql());
|
||||
this.cachedSql = NamedParameterUtils.parseSqlStatement(resolveSql());
|
||||
}
|
||||
return this.cachedSql;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -107,7 +107,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* @return a List of objects, one per row of the ResultSet. Normally all these
|
||||
* will be of the same class, although it is possible to use different types.
|
||||
*/
|
||||
public List<T> execute(Object[] params, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
public List<T> execute(@Nullable Object[] params, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
validateParameters(params);
|
||||
RowMapper<T> rowMapper = newRowMapper(params, context);
|
||||
return getJdbcTemplate().query(newPreparedStatementCreator(params), rowMapper);
|
||||
@@ -135,7 +135,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* Convenient method to execute without parameters nor context.
|
||||
*/
|
||||
public List<T> execute() throws DataAccessException {
|
||||
return execute((Object[]) null);
|
||||
return execute((Object[]) null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -250,7 +250,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* @see org.springframework.dao.support.DataAccessUtils#singleResult
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(Object[] params, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
public T findObject(@Nullable Object[] params, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
List<T> results = execute(params, context);
|
||||
return DataAccessUtils.singleResult(results);
|
||||
}
|
||||
@@ -258,6 +258,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
/**
|
||||
* Convenient method to find a single object without context.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(Object... params) throws DataAccessException {
|
||||
return findObject(params, null);
|
||||
}
|
||||
@@ -266,6 +267,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* Convenient method to find a single object given a single int parameter
|
||||
* and a context.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(int p1, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
return findObject(new Object[] {p1}, context);
|
||||
}
|
||||
@@ -273,6 +275,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
/**
|
||||
* Convenient method to find a single object given a single int parameter.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(int p1) throws DataAccessException {
|
||||
return findObject(p1, null);
|
||||
}
|
||||
@@ -281,6 +284,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* Convenient method to find a single object given two int parameters
|
||||
* and a context.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(int p1, int p2, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
return findObject(new Object[] {p1, p2}, context);
|
||||
}
|
||||
@@ -288,6 +292,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
/**
|
||||
* Convenient method to find a single object given two int parameters.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(int p1, int p2) throws DataAccessException {
|
||||
return findObject(p1, p2, null);
|
||||
}
|
||||
@@ -296,6 +301,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* Convenient method to find a single object given a single long parameter
|
||||
* and a context.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(long p1, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
return findObject(new Object[] {p1}, context);
|
||||
}
|
||||
@@ -303,6 +309,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
/**
|
||||
* Convenient method to find a single object given a single long parameter.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(long p1) throws DataAccessException {
|
||||
return findObject(p1, null);
|
||||
}
|
||||
@@ -311,6 +318,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* Convenient method to find a single object given a single String parameter
|
||||
* and a context.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(String p1, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
return findObject(new Object[] {p1}, context);
|
||||
}
|
||||
@@ -318,6 +326,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
/**
|
||||
* Convenient method to find a single object given a single String parameter.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObject(String p1) throws DataAccessException {
|
||||
return findObject(p1, null);
|
||||
}
|
||||
@@ -333,6 +342,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* @return a List of objects, one per row of the ResultSet. Normally all these
|
||||
* will be of the same class, although it is possible to use different types.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObjectByNamedParam(Map<String, ?> paramMap, @Nullable Map<?, ?> context) throws DataAccessException {
|
||||
List<T> results = executeByNamedParam(paramMap, context);
|
||||
return DataAccessUtils.singleResult(results);
|
||||
@@ -344,6 +354,7 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* matching named parameters specified in the SQL statement.
|
||||
* Ordering is not significant.
|
||||
*/
|
||||
@Nullable
|
||||
public T findObjectByNamedParam(Map<String, ?> paramMap) throws DataAccessException {
|
||||
return findObjectByNamedParam(paramMap, null);
|
||||
}
|
||||
@@ -360,6 +371,6 @@ public abstract class SqlQuery<T> extends SqlOperation {
|
||||
* but it can be useful for creating the objects of the result list.
|
||||
* @see #execute
|
||||
*/
|
||||
protected abstract RowMapper<T> newRowMapper(@Nullable Object[] parameters, Map<?, ?> context);
|
||||
protected abstract RowMapper<T> newRowMapper(@Nullable Object[] parameters, @Nullable Map<?, ?> context);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -149,10 +149,10 @@ public class SqlUpdate extends SqlOperation {
|
||||
*/
|
||||
protected void checkRowsAffected(int rowsAffected) throws JdbcUpdateAffectedIncorrectNumberOfRowsException {
|
||||
if (this.maxRowsAffected > 0 && rowsAffected > this.maxRowsAffected) {
|
||||
throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(getSql(), this.maxRowsAffected, rowsAffected);
|
||||
throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(resolveSql(), this.maxRowsAffected, rowsAffected);
|
||||
}
|
||||
if (this.requiredRowsAffected > 0 && rowsAffected != this.requiredRowsAffected) {
|
||||
throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(getSql(), this.requiredRowsAffected, rowsAffected);
|
||||
throw new JdbcUpdateAffectedIncorrectNumberOfRowsException(resolveSql(), this.requiredRowsAffected, rowsAffected);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -194,7 +194,7 @@ public class SqlUpdate extends SqlOperation {
|
||||
* Convenience method to execute an update with no parameters.
|
||||
*/
|
||||
public int update() throws DataAccessException {
|
||||
return update((Object[]) null);
|
||||
return update(new Object[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.jdbc.object;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
@@ -26,7 +25,6 @@ import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.ParameterMapper;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Superclass for object abstractions of RDBMS stored procedures.
|
||||
@@ -104,14 +102,13 @@ public abstract class StoredProcedure extends SqlCall {
|
||||
* a convenience method where the order of the passed in parameter values
|
||||
* must match the order that the parameters where declared in.
|
||||
* @param inParams variable number of input parameters. Output parameters should
|
||||
* not be included in this map.
|
||||
* It is legal for values to be {@code null}, and this will produce the
|
||||
* correct behavior using a NULL argument to the stored procedure.
|
||||
* not be included in this map. It is legal for values to be {@code null}, and this
|
||||
* will produce the correct behavior using a NULL argument to the stored procedure.
|
||||
* @return map of output params, keyed by name as in parameter declarations.
|
||||
* Output parameters will appear here, with their values after the
|
||||
* stored procedure has been called.
|
||||
* Output parameters will appear here, with their values after the stored procedure
|
||||
* has been called.
|
||||
*/
|
||||
public Map<String, Object> execute(@Nullable Object... inParams) {
|
||||
public Map<String, Object> execute(Object... inParams) {
|
||||
Map<String, Object> paramsToUse = new HashMap<>();
|
||||
validateParameters(inParams);
|
||||
int i = 0;
|
||||
@@ -139,7 +136,7 @@ public abstract class StoredProcedure extends SqlCall {
|
||||
* Output parameters will appear here, with their values after the
|
||||
* stored procedure has been called.
|
||||
*/
|
||||
public Map<String, Object> execute(@Nullable Map<String, ?> inParams) throws DataAccessException {
|
||||
public Map<String, Object> execute(Map<String, ?> inParams) throws DataAccessException {
|
||||
validateParameters(inParams.values().toArray());
|
||||
return getJdbcTemplate().call(newCallableStatementCreator(inParams), getDeclaredParameters());
|
||||
}
|
||||
@@ -160,7 +157,7 @@ public abstract class StoredProcedure extends SqlCall {
|
||||
* Output parameters will appear here, with their values after the
|
||||
* stored procedure has been called.
|
||||
*/
|
||||
public Map<String, Object> execute(@Nullable ParameterMapper inParamMapper) throws DataAccessException {
|
||||
public Map<String, Object> execute(ParameterMapper inParamMapper) throws DataAccessException {
|
||||
checkCompiled();
|
||||
return getJdbcTemplate().call(newCallableStatementCreator(inParamMapper), getDeclaredParameters());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -61,7 +61,7 @@ public abstract class UpdatableSqlQuery<T> extends SqlQuery<T> {
|
||||
* implementation of the {@code updateRow()} method.
|
||||
*/
|
||||
@Override
|
||||
protected RowMapper<T> newRowMapper(@Nullable Object[] parameters, Map<?, ?> context) {
|
||||
protected RowMapper<T> newRowMapper(@Nullable Object[] parameters, @Nullable Map<?, ?> context) {
|
||||
return new RowMapperImpl(context);
|
||||
}
|
||||
|
||||
@@ -91,7 +91,7 @@ public abstract class UpdatableSqlQuery<T> extends SqlQuery<T> {
|
||||
|
||||
private final Map<?, ?> context;
|
||||
|
||||
public RowMapperImpl(Map<?, ?> context) {
|
||||
public RowMapperImpl(@Nullable Map<?, ?> context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -63,7 +63,7 @@ public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExcep
|
||||
* {@link #getFallbackTranslator() fallback translator} if necessary.
|
||||
*/
|
||||
@Override
|
||||
public DataAccessException translate(String task, @Nullable String sql, SQLException ex) {
|
||||
public DataAccessException translate(@Nullable String task, @Nullable String sql, SQLException ex) {
|
||||
Assert.notNull(ex, "Cannot translate a null SQLException");
|
||||
if (task == null) {
|
||||
task = "";
|
||||
@@ -92,13 +92,13 @@ public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExcep
|
||||
* is allowed to return {@code null} to indicate that no exception match has
|
||||
* been found and that fallback translation should kick in.
|
||||
* @param task readable text describing the task being attempted
|
||||
* @param sql SQL query or update that caused the problem (may be {@code null})
|
||||
* @param sql SQL query or update that caused the problem
|
||||
* @param ex the offending {@code SQLException}
|
||||
* @return the DataAccessException, wrapping the {@code SQLException};
|
||||
* or {@code null} if no exception match found
|
||||
*/
|
||||
@Nullable
|
||||
protected abstract DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex);
|
||||
protected abstract DataAccessException doTranslate(String task, String sql, SQLException ex);
|
||||
|
||||
|
||||
/**
|
||||
@@ -106,11 +106,11 @@ public abstract class AbstractFallbackSQLExceptionTranslator implements SQLExcep
|
||||
* <p>To be called by translator subclasses when creating an instance of a generic
|
||||
* {@link org.springframework.dao.DataAccessException} class.
|
||||
* @param task readable text describing the task being attempted
|
||||
* @param sql the SQL statement that caused the problem (may be {@code null})
|
||||
* @param sql the SQL statement that caused the problem
|
||||
* @param ex the offending {@code SQLException}
|
||||
* @return the message {@code String} to use
|
||||
*/
|
||||
protected String buildMessage(String task, @Nullable String sql, SQLException ex) {
|
||||
protected String buildMessage(String task, String sql, SQLException ex) {
|
||||
return task + "; SQL [" + sql + "]; " + ex.getMessage();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.jdbc.support;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
@@ -63,6 +64,7 @@ public class CustomSQLErrorCodesTranslation {
|
||||
/**
|
||||
* Return the exception class for the specified error codes.
|
||||
*/
|
||||
@Nullable
|
||||
public Class<?> getExceptionClass() {
|
||||
return this.exceptionClass;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -22,6 +22,8 @@ import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Base class for {@link org.springframework.jdbc.core.JdbcTemplate} and
|
||||
@@ -57,10 +59,23 @@ public abstract class JdbcAccessor implements InitializingBean {
|
||||
/**
|
||||
* Return the DataSource used by this template.
|
||||
*/
|
||||
@Nullable
|
||||
public DataSource getDataSource() {
|
||||
return this.dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain the DataSource for actual use.
|
||||
* @return the DataSource (never {@code null})
|
||||
* @throws IllegalStateException in case of no DataSource set
|
||||
* @since 5.0
|
||||
*/
|
||||
protected DataSource obtainDataSource() {
|
||||
DataSource dataSource = getDataSource();
|
||||
Assert.state(dataSource != null, "No DataSource set");
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify the database product name for the DataSource that this accessor uses.
|
||||
* This allows to initialize a SQLErrorCodeSQLExceptionTranslator without
|
||||
|
||||
@@ -29,7 +29,6 @@ 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;
|
||||
@@ -261,6 +260,7 @@ public abstract class JdbcUtils {
|
||||
* @see java.sql.Clob
|
||||
* @see java.sql.Timestamp
|
||||
*/
|
||||
@Nullable
|
||||
public static Object getResultSetValue(ResultSet rs, int index) throws SQLException {
|
||||
Object obj = rs.getObject(index);
|
||||
String className = null;
|
||||
@@ -310,16 +310,13 @@ public abstract class JdbcUtils {
|
||||
* the DatabaseMetaDataCallback's {@code processMetaData} method
|
||||
* @throws MetaDataAccessException if meta data access failed
|
||||
*/
|
||||
@Nullable
|
||||
public static Object extractDatabaseMetaData(DataSource dataSource, DatabaseMetaDataCallback action)
|
||||
throws MetaDataAccessException {
|
||||
|
||||
Connection con = null;
|
||||
try {
|
||||
con = DataSourceUtils.getConnection(dataSource);
|
||||
if (con == null) {
|
||||
// should only happen in test environments
|
||||
throw new MetaDataAccessException("Connection returned by DataSource [" + dataSource + "] was null");
|
||||
}
|
||||
DatabaseMetaData metaData = con.getMetaData();
|
||||
if (metaData == null) {
|
||||
// should only happen in test environments
|
||||
@@ -352,32 +349,31 @@ public abstract class JdbcUtils {
|
||||
* or failed to invoke the specified method
|
||||
* @see java.sql.DatabaseMetaData
|
||||
*/
|
||||
public static Object extractDatabaseMetaData(DataSource dataSource, final String metaDataMethodName)
|
||||
@SuppressWarnings("unchecked")
|
||||
@Nullable
|
||||
public static <T> T extractDatabaseMetaData(DataSource dataSource, final String metaDataMethodName)
|
||||
throws MetaDataAccessException {
|
||||
|
||||
return extractDatabaseMetaData(dataSource,
|
||||
new DatabaseMetaDataCallback() {
|
||||
@Override
|
||||
public Object processMetaData(DatabaseMetaData dbmd) throws SQLException, MetaDataAccessException {
|
||||
try {
|
||||
Method method = DatabaseMetaData.class.getMethod(metaDataMethodName, (Class[]) null);
|
||||
return method.invoke(dbmd, (Object[]) null);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new MetaDataAccessException("No method named '" + metaDataMethodName +
|
||||
"' found on DatabaseMetaData instance [" + dbmd + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new MetaDataAccessException(
|
||||
"Could not access DatabaseMetaData method '" + metaDataMethodName + "'", ex);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
if (ex.getTargetException() instanceof SQLException) {
|
||||
throw (SQLException) ex.getTargetException();
|
||||
}
|
||||
throw new MetaDataAccessException(
|
||||
"Invocation of DatabaseMetaData method '" + metaDataMethodName + "' failed", ex);
|
||||
return (T) extractDatabaseMetaData(dataSource,
|
||||
dbmd -> {
|
||||
try {
|
||||
Method method = DatabaseMetaData.class.getMethod(metaDataMethodName, (Class[]) null);
|
||||
return method.invoke(dbmd, (Object[]) null);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
throw new MetaDataAccessException("No method named '" + metaDataMethodName +
|
||||
"' found on DatabaseMetaData instance [" + dbmd + "]", ex);
|
||||
}
|
||||
catch (IllegalAccessException ex) {
|
||||
throw new MetaDataAccessException(
|
||||
"Could not access DatabaseMetaData method '" + metaDataMethodName + "'", ex);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
if (ex.getTargetException() instanceof SQLException) {
|
||||
throw (SQLException) ex.getTargetException();
|
||||
}
|
||||
throw new MetaDataAccessException(
|
||||
"Invocation of DatabaseMetaData method '" + metaDataMethodName + "' failed", ex);
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -417,7 +413,8 @@ public abstract class JdbcUtils {
|
||||
* @param source the name as provided in database metadata
|
||||
* @return the common name to be used
|
||||
*/
|
||||
public static String commonDatabaseName(String source) {
|
||||
@Nullable
|
||||
public static String commonDatabaseName(@Nullable String source) {
|
||||
String name = source;
|
||||
if (source != null && source.startsWith("DB2")) {
|
||||
name = "DB2";
|
||||
@@ -464,12 +461,12 @@ public abstract class JdbcUtils {
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a column name with underscores to the corresponding property name using "camel case". A name
|
||||
* like "customer_number" would match a "customerNumber" property name.
|
||||
* Convert a column name with underscores to the corresponding property name using "camel case".
|
||||
* A name like "customer_number" would match a "customerNumber" property name.
|
||||
* @param name the column name to be converted
|
||||
* @return the name using "camel case"
|
||||
*/
|
||||
public static String convertUnderscoreNameToPropertyName(String name) {
|
||||
public static String convertUnderscoreNameToPropertyName(@Nullable String name) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
boolean nextIsUpper = false;
|
||||
if (name != null && name.length() > 0) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,7 +20,6 @@ import java.lang.reflect.Constructor;
|
||||
import java.sql.BatchUpdateException;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
@@ -167,7 +166,7 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
|
||||
|
||||
|
||||
@Override
|
||||
protected DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex) {
|
||||
protected DataAccessException doTranslate(String task, String sql, SQLException ex) {
|
||||
SQLException sqlEx = ex;
|
||||
if (sqlEx instanceof BatchUpdateException && sqlEx.getNextException() != null) {
|
||||
SQLException nestedSqlEx = sqlEx.getNextException();
|
||||
@@ -315,6 +314,7 @@ public class SQLErrorCodeSQLExceptionTranslator extends AbstractFallbackSQLExcep
|
||||
* sqlEx parameter as a nested root cause.
|
||||
* @see CustomSQLErrorCodesTranslation#setExceptionClass
|
||||
*/
|
||||
@Nullable
|
||||
protected DataAccessException createCustomException(
|
||||
String task, @Nullable String sql, SQLException sqlEx, Class<?> exceptionClass) {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.support;
|
||||
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
@@ -71,6 +72,7 @@ public class SQLErrorCodes {
|
||||
this.databaseProductNames = new String[] {databaseProductName};
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getDatabaseProductName() {
|
||||
return (this.databaseProductNames != null && this.databaseProductNames.length > 0 ?
|
||||
this.databaseProductNames[0] : null);
|
||||
@@ -184,11 +186,12 @@ public class SQLErrorCodes {
|
||||
this.customTranslations = customTranslations;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public CustomSQLErrorCodesTranslation[] getCustomTranslations() {
|
||||
return this.customTranslations;
|
||||
}
|
||||
|
||||
public void setCustomSqlExceptionTranslatorClass(Class<? extends SQLExceptionTranslator> customTranslatorClass) {
|
||||
public void setCustomSqlExceptionTranslatorClass(@Nullable Class<? extends SQLExceptionTranslator> customTranslatorClass) {
|
||||
if (customTranslatorClass != null) {
|
||||
try {
|
||||
this.customSqlExceptionTranslator =
|
||||
@@ -207,6 +210,7 @@ public class SQLErrorCodes {
|
||||
this.customSqlExceptionTranslator = customSqlExceptionTranslator;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public SQLExceptionTranslator getCustomSqlExceptionTranslator() {
|
||||
return this.customSqlExceptionTranslator;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -18,7 +18,6 @@ package org.springframework.jdbc.support;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -211,16 +210,16 @@ public class SQLErrorCodesFactory {
|
||||
if (sec == null) {
|
||||
// We could not find it - got to look it up.
|
||||
try {
|
||||
String name = (String) JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName");
|
||||
String name = JdbcUtils.extractDatabaseMetaData(dataSource, "getDatabaseProductName");
|
||||
if (name != null) {
|
||||
return registerDatabase(dataSource, name);
|
||||
}
|
||||
}
|
||||
catch (MetaDataAccessException ex) {
|
||||
logger.warn("Error while extracting database name - falling back to empty error codes", ex);
|
||||
// Fallback is to return an empty SQLErrorCodes instance.
|
||||
return new SQLErrorCodes();
|
||||
}
|
||||
// Fallback is to return an empty SQLErrorCodes instance.
|
||||
return new SQLErrorCodes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -64,7 +64,7 @@ public class SQLExceptionSubclassTranslator extends AbstractFallbackSQLException
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
protected DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex) {
|
||||
protected DataAccessException doTranslate(String task, String sql, SQLException ex) {
|
||||
if (ex instanceof SQLTransientException) {
|
||||
if (ex instanceof SQLTransientConnectionException) {
|
||||
return new TransientDataAccessResourceException(buildMessage(task, sql, ex), ex);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -52,6 +52,6 @@ public interface SQLExceptionTranslator {
|
||||
* @see org.springframework.dao.DataAccessException#getRootCause()
|
||||
*/
|
||||
@Nullable
|
||||
DataAccessException translate(String task, @Nullable String sql, SQLException ex);
|
||||
DataAccessException translate(@Nullable String task, @Nullable String sql, SQLException ex);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -88,7 +88,7 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
|
||||
|
||||
|
||||
@Override
|
||||
protected DataAccessException doTranslate(String task, @Nullable String sql, SQLException ex) {
|
||||
protected DataAccessException doTranslate(String task, String sql, SQLException ex) {
|
||||
// First, the getSQLState check...
|
||||
String sqlState = getSqlState(ex);
|
||||
if (sqlState != null && sqlState.length() >= 2) {
|
||||
@@ -131,6 +131,7 @@ public class SQLStateSQLExceptionTranslator extends AbstractFallbackSQLException
|
||||
* is to be extracted
|
||||
* @return the SQL state code
|
||||
*/
|
||||
@Nullable
|
||||
private String getSqlState(SQLException ex) {
|
||||
String sqlState = ex.getSQLState();
|
||||
if (sqlState == null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -77,17 +77,21 @@ public class TemporaryLobCreator implements LobCreator {
|
||||
PreparedStatement ps, int paramIndex, @Nullable InputStream binaryStream, int contentLength)
|
||||
throws SQLException {
|
||||
|
||||
Blob blob = ps.getConnection().createBlob();
|
||||
try {
|
||||
FileCopyUtils.copy(binaryStream, blob.setBinaryStream(1));
|
||||
if (binaryStream != null) {
|
||||
Blob blob = ps.getConnection().createBlob();
|
||||
try {
|
||||
FileCopyUtils.copy(binaryStream, blob.setBinaryStream(1));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||
}
|
||||
this.temporaryBlobs.add(blob);
|
||||
ps.setBlob(paramIndex, blob);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||
else {
|
||||
ps.setBlob(paramIndex, (Blob) null);
|
||||
}
|
||||
|
||||
this.temporaryBlobs.add(blob);
|
||||
ps.setBlob(paramIndex, blob);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(binaryStream != null ?
|
||||
"Copied binary stream into temporary BLOB with length " + contentLength :
|
||||
@@ -116,17 +120,21 @@ public class TemporaryLobCreator implements LobCreator {
|
||||
PreparedStatement ps, int paramIndex, @Nullable InputStream asciiStream, int contentLength)
|
||||
throws SQLException {
|
||||
|
||||
Clob clob = ps.getConnection().createClob();
|
||||
try {
|
||||
FileCopyUtils.copy(asciiStream, clob.setAsciiStream(1));
|
||||
if (asciiStream != null) {
|
||||
Clob clob = ps.getConnection().createClob();
|
||||
try {
|
||||
FileCopyUtils.copy(asciiStream, clob.setAsciiStream(1));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||
}
|
||||
this.temporaryClobs.add(clob);
|
||||
ps.setClob(paramIndex, clob);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||
else {
|
||||
ps.setClob(paramIndex, (Clob) null);
|
||||
}
|
||||
|
||||
this.temporaryClobs.add(clob);
|
||||
ps.setClob(paramIndex, clob);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(asciiStream != null ?
|
||||
"Copied ASCII stream into temporary CLOB with length " + contentLength :
|
||||
@@ -139,17 +147,21 @@ public class TemporaryLobCreator implements LobCreator {
|
||||
PreparedStatement ps, int paramIndex, @Nullable Reader characterStream, int contentLength)
|
||||
throws SQLException {
|
||||
|
||||
Clob clob = ps.getConnection().createClob();
|
||||
try {
|
||||
FileCopyUtils.copy(characterStream, clob.setCharacterStream(1));
|
||||
if (characterStream != null) {
|
||||
Clob clob = ps.getConnection().createClob();
|
||||
try {
|
||||
FileCopyUtils.copy(characterStream, clob.setCharacterStream(1));
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||
}
|
||||
this.temporaryClobs.add(clob);
|
||||
ps.setClob(paramIndex, clob);
|
||||
}
|
||||
catch (IOException ex) {
|
||||
throw new DataAccessResourceFailureException("Could not copy into LOB stream", ex);
|
||||
else {
|
||||
ps.setClob(paramIndex, (Clob) null);
|
||||
}
|
||||
|
||||
this.temporaryClobs.add(clob);
|
||||
ps.setClob(paramIndex, clob);
|
||||
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(characterStream != null ?
|
||||
"Copied character stream into temporary CLOB with length " + contentLength :
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -31,6 +31,7 @@ import javax.xml.transform.dom.DOMSource;
|
||||
import org.w3c.dom.Document;
|
||||
|
||||
import org.springframework.dao.DataAccessResourceFailureException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Default implementation of the {@link SqlXmlHandler} interface.
|
||||
@@ -88,7 +89,9 @@ public class Jdbc4SqlXmlHandler implements SqlXmlHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Source getXmlAsSource(ResultSet rs, String columnName, Class<? extends Source> sourceClass) throws SQLException {
|
||||
public Source getXmlAsSource(ResultSet rs, String columnName, @Nullable Class<? extends Source> sourceClass)
|
||||
throws SQLException {
|
||||
|
||||
SQLXML xmlObject = rs.getSQLXML(columnName);
|
||||
if (xmlObject == null) {
|
||||
return null;
|
||||
@@ -97,7 +100,9 @@ public class Jdbc4SqlXmlHandler implements SqlXmlHandler {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Source getXmlAsSource(ResultSet rs, int columnIndex, Class<? extends Source> sourceClass) throws SQLException {
|
||||
public Source getXmlAsSource(ResultSet rs, int columnIndex, @Nullable Class<? extends Source> sourceClass)
|
||||
throws SQLException {
|
||||
|
||||
SQLXML xmlObject = rs.getSQLXML(columnIndex);
|
||||
if (xmlObject == null) {
|
||||
return null;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -156,7 +156,7 @@ public interface SqlXmlHandler {
|
||||
* @see java.sql.SQLXML#getSource
|
||||
*/
|
||||
@Nullable
|
||||
Source getXmlAsSource(ResultSet rs, String columnName, Class<? extends Source> sourceClass) throws SQLException;
|
||||
Source getXmlAsSource(ResultSet rs, String columnName, @Nullable Class<? extends Source> sourceClass) throws SQLException;
|
||||
|
||||
/**
|
||||
* Retrieve the given column as Source implemented using the specified source class
|
||||
@@ -172,7 +172,7 @@ public interface SqlXmlHandler {
|
||||
* @see java.sql.SQLXML#getSource
|
||||
*/
|
||||
@Nullable
|
||||
Source getXmlAsSource(ResultSet rs, int columnIndex, Class<? extends Source> sourceClass) throws SQLException;
|
||||
Source getXmlAsSource(ResultSet rs, int columnIndex, @Nullable Class<? extends Source> sourceClass) throws SQLException;
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user