Consistent nullability in DataAccessUtils through nullableSingleResult
Issue: SPR-16225
This commit is contained in:
parent
a8323f6a27
commit
b1c657fa4b
|
|
@ -141,7 +141,8 @@ public interface JdbcOperations {
|
|||
* {@code null} as argument array.
|
||||
* @param sql SQL query to execute
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @return the single mapped object (may be {@code null} if the given
|
||||
* {@link RowMapper} returned {@code} null)
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if there is any problem executing the query
|
||||
|
|
@ -371,6 +372,7 @@ public interface JdbcOperations {
|
|||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return an arbitrary result object, as returned by the ResultSetExtractor
|
||||
* @throws DataAccessException if the query fails
|
||||
* @since 3.0.1
|
||||
*/
|
||||
@Nullable
|
||||
<T> T query(String sql, ResultSetExtractor<T> rse, @Nullable Object... args) throws DataAccessException;
|
||||
|
|
@ -441,6 +443,7 @@ public interface JdbcOperations {
|
|||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @throws DataAccessException if the query fails
|
||||
* @since 3.0.1
|
||||
*/
|
||||
void query(String sql, RowCallbackHandler rch, @Nullable Object... args) throws DataAccessException;
|
||||
|
||||
|
|
@ -514,6 +517,7 @@ public interface JdbcOperations {
|
|||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return the result List, containing mapped objects
|
||||
* @throws DataAccessException if the query fails
|
||||
* @since 3.0.1
|
||||
*/
|
||||
<T> List<T> query(String sql, RowMapper<T> rowMapper, @Nullable Object... args) throws DataAccessException;
|
||||
|
||||
|
|
@ -527,7 +531,8 @@ public interface JdbcOperations {
|
|||
* @param argTypes SQL types of the arguments
|
||||
* (constants from {@code java.sql.Types})
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @return the single mapped object (may be {@code null} if the given
|
||||
* {@link RowMapper} returned {@code} null)
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if the query fails
|
||||
|
|
@ -546,7 +551,8 @@ public interface JdbcOperations {
|
|||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @return the single mapped object (may be {@code null} if the given
|
||||
* {@link RowMapper} returned {@code} null)
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if the query fails
|
||||
|
|
@ -564,10 +570,12 @@ public interface JdbcOperations {
|
|||
* (leaving it to the PreparedStatement to guess the corresponding SQL type);
|
||||
* may also contain {@link SqlParameterValue} objects which indicate not
|
||||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return the single mapped object
|
||||
* @return the single mapped object (may be {@code null} if the given
|
||||
* {@link RowMapper} returned {@code} null)
|
||||
* @throws IncorrectResultSizeDataAccessException if the query does not
|
||||
* return exactly one row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @since 3.0.1
|
||||
*/
|
||||
@Nullable
|
||||
<T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args) throws DataAccessException;
|
||||
|
|
@ -628,6 +636,7 @@ public interface JdbcOperations {
|
|||
* @throws IncorrectResultSizeDataAccessException if the query does not return
|
||||
* exactly one row, or does not return exactly one column in that row
|
||||
* @throws DataAccessException if the query fails
|
||||
* @since 3.0.1
|
||||
* @see #queryForObject(String, Class)
|
||||
*/
|
||||
@Nullable
|
||||
|
|
@ -728,6 +737,7 @@ public interface JdbcOperations {
|
|||
* only the argument value but also the SQL type and optionally the scale
|
||||
* @return a List of objects that match the specified element type
|
||||
* @throws DataAccessException if the query fails
|
||||
* @since 3.0.1
|
||||
* @see #queryForList(String, Class)
|
||||
* @see SingleColumnRowMapper
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -465,7 +465,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
|||
@Nullable
|
||||
public <T> T queryForObject(String sql, RowMapper<T> rowMapper) throws DataAccessException {
|
||||
List<T> results = query(sql, rowMapper);
|
||||
return DataAccessUtils.requiredSingleResult(results);
|
||||
return DataAccessUtils.nullableSingleResult(results);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -762,21 +762,21 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
|
|||
throws DataAccessException {
|
||||
|
||||
List<T> results = query(sql, args, argTypes, new RowMapperResultSetExtractor<>(rowMapper, 1));
|
||||
return DataAccessUtils.requiredSingleResult(results);
|
||||
return DataAccessUtils.nullableSingleResult(results);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
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);
|
||||
return DataAccessUtils.nullableSingleResult(results);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public <T> T queryForObject(String sql, RowMapper<T> rowMapper, @Nullable Object... args) throws DataAccessException {
|
||||
List<T> results = query(sql, args, new RowMapperResultSetExtractor<>(rowMapper, 1));
|
||||
return DataAccessUtils.requiredSingleResult(results);
|
||||
return DataAccessUtils.nullableSingleResult(results);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -56,7 +56,7 @@ public interface RowMapper<T> {
|
|||
* the ResultSet; it is only supposed to map values of the current row.
|
||||
* @param rs the ResultSet to map (pre-initialized for the current row)
|
||||
* @param rowNum the number of the current row
|
||||
* @return the result object for the current row
|
||||
* @return the result object for the current row (may be {@code null})
|
||||
* @throws SQLException if a SQLException is encountered getting
|
||||
* column values (that is, there's no need to catch SQLException)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -233,7 +233,8 @@ public interface NamedParameterJdbcOperations {
|
|||
* @param sql SQL query to execute
|
||||
* @param paramSource container of arguments to bind to the query
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @return the single mapped object (may be {@code null} if the given
|
||||
* {@link RowMapper} returned {@code} null)
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
|
|
@ -251,7 +252,8 @@ public interface NamedParameterJdbcOperations {
|
|||
* @param paramMap map of parameters to bind to the query
|
||||
* (leaving it to the PreparedStatement to guess the corresponding SQL type)
|
||||
* @param rowMapper object that will map one object per row
|
||||
* @return the single mapped object
|
||||
* @return the single mapped object (may be {@code null} if the given
|
||||
* {@link RowMapper} returned {@code} null)
|
||||
* @throws org.springframework.dao.IncorrectResultSizeDataAccessException
|
||||
* if the query does not return exactly one row, or does not return exactly
|
||||
* one column in that row
|
||||
|
|
|
|||
|
|
@ -217,7 +217,7 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations
|
|||
throws DataAccessException {
|
||||
|
||||
List<T> results = getJdbcOperations().query(getPreparedStatementCreator(sql, paramSource), rowMapper);
|
||||
return DataAccessUtils.requiredSingleResult(results);
|
||||
return DataAccessUtils.nullableSingleResult(results);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
|||
|
|
@ -47,12 +47,11 @@ public abstract class DataAccessUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static <T> T singleResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
|
||||
int size = (results != null ? results.size() : 0);
|
||||
if (size == 0) {
|
||||
if (CollectionUtils.isEmpty(results)) {
|
||||
return null;
|
||||
}
|
||||
if (results.size() > 1) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, size);
|
||||
throw new IncorrectResultSizeDataAccessException(1, results.size());
|
||||
}
|
||||
return results.iterator().next();
|
||||
}
|
||||
|
|
@ -60,21 +59,45 @@ public abstract class DataAccessUtils {
|
|||
/**
|
||||
* Return a single result object from the given Collection.
|
||||
* <p>Throws an exception if 0 or more than 1 element found.
|
||||
* @param results the result Collection (can be {@code null})
|
||||
* @param results the result Collection (can be {@code null}
|
||||
* but is not expected to contain {@code null} elements)
|
||||
* @return the single result object
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one
|
||||
* element has been found in the given Collection
|
||||
* @throws EmptyResultDataAccessException if no element at all
|
||||
* has been found in the given Collection
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T requiredSingleResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
|
||||
int size = (results != null ? results.size() : 0);
|
||||
if (size == 0) {
|
||||
if (CollectionUtils.isEmpty(results)) {
|
||||
throw new EmptyResultDataAccessException(1);
|
||||
}
|
||||
if (results.size() > 1) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, size);
|
||||
throw new IncorrectResultSizeDataAccessException(1, results.size());
|
||||
}
|
||||
return results.iterator().next();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a single result object from the given Collection.
|
||||
* <p>Throws an exception if 0 or more than 1 element found.
|
||||
* @param results the result Collection (can be {@code null}
|
||||
* and is also expected to contain {@code null} elements)
|
||||
* @return the single result object
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one
|
||||
* element has been found in the given Collection
|
||||
* @throws EmptyResultDataAccessException if no element at all
|
||||
* has been found in the given Collection
|
||||
* @since 5.0.2
|
||||
*/
|
||||
@Nullable
|
||||
public static <T> T nullableSingleResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
|
||||
// This is identical to the requiredSingleResult implementation but differs in the
|
||||
// semantics of the incoming Collection (which we currently can't formally express)
|
||||
if (CollectionUtils.isEmpty(results)) {
|
||||
throw new EmptyResultDataAccessException(1);
|
||||
}
|
||||
if (results.size() > 1) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, results.size());
|
||||
}
|
||||
return results.iterator().next();
|
||||
}
|
||||
|
|
@ -91,12 +114,11 @@ public abstract class DataAccessUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static <T> T uniqueResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
|
||||
int size = (results != null ? results.size() : 0);
|
||||
if (size == 0) {
|
||||
if (CollectionUtils.isEmpty(results)) {
|
||||
return null;
|
||||
}
|
||||
if (!CollectionUtils.hasUniqueObject(results)) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, size);
|
||||
throw new IncorrectResultSizeDataAccessException(1, results.size());
|
||||
}
|
||||
return results.iterator().next();
|
||||
}
|
||||
|
|
@ -104,7 +126,8 @@ public abstract class DataAccessUtils {
|
|||
/**
|
||||
* Return a unique result object from the given Collection.
|
||||
* <p>Throws an exception if 0 or more than 1 instance found.
|
||||
* @param results the result Collection (can be {@code null})
|
||||
* @param results the result Collection (can be {@code null}
|
||||
* but is not expected to contain {@code null} elements)
|
||||
* @return the unique result object
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one
|
||||
* result object has been found in the given Collection
|
||||
|
|
@ -113,12 +136,11 @@ public abstract class DataAccessUtils {
|
|||
* @see org.springframework.util.CollectionUtils#hasUniqueObject
|
||||
*/
|
||||
public static <T> T requiredUniqueResult(@Nullable Collection<T> results) throws IncorrectResultSizeDataAccessException {
|
||||
int size = (results != null ? results.size() : 0);
|
||||
if (size == 0) {
|
||||
if (CollectionUtils.isEmpty(results)) {
|
||||
throw new EmptyResultDataAccessException(1);
|
||||
}
|
||||
if (!CollectionUtils.hasUniqueObject(results)) {
|
||||
throw new IncorrectResultSizeDataAccessException(1, size);
|
||||
throw new IncorrectResultSizeDataAccessException(1, results.size());
|
||||
}
|
||||
return results.iterator().next();
|
||||
}
|
||||
|
|
@ -128,7 +150,8 @@ public abstract class DataAccessUtils {
|
|||
* Throws an exception if 0 or more than 1 result objects found,
|
||||
* of if the unique result object is not convertible to the
|
||||
* specified required type.
|
||||
* @param results the result Collection (can be {@code null})
|
||||
* @param results the result Collection (can be {@code null}
|
||||
* but is not expected to contain {@code null} elements)
|
||||
* @return the unique result object
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one
|
||||
* result object has been found in the given Collection
|
||||
|
|
@ -167,7 +190,8 @@ public abstract class DataAccessUtils {
|
|||
* Return a unique int result from the given Collection.
|
||||
* Throws an exception if 0 or more than 1 result objects found,
|
||||
* of if the unique result object is not convertible to an int.
|
||||
* @param results the result Collection (can be {@code null})
|
||||
* @param results the result Collection (can be {@code null}
|
||||
* but is not expected to contain {@code null} elements)
|
||||
* @return the unique int result
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one
|
||||
* result object has been found in the given Collection
|
||||
|
|
@ -186,7 +210,8 @@ public abstract class DataAccessUtils {
|
|||
* Return a unique long result from the given Collection.
|
||||
* Throws an exception if 0 or more than 1 result objects found,
|
||||
* of if the unique result object is not convertible to a long.
|
||||
* @param results the result Collection (can be {@code null})
|
||||
* @param results the result Collection (can be {@code null}
|
||||
* but is not expected to contain {@code null} elements)
|
||||
* @return the unique long result
|
||||
* @throws IncorrectResultSizeDataAccessException if more than one
|
||||
* result object has been found in the given Collection
|
||||
|
|
@ -204,11 +229,11 @@ public abstract class DataAccessUtils {
|
|||
|
||||
/**
|
||||
* Return a translated exception if this is appropriate,
|
||||
* otherwise return the input exception.
|
||||
* @param rawException exception we may wish to translate
|
||||
* otherwise return the given exception as-is.
|
||||
* @param rawException an exception that we may wish to translate
|
||||
* @param pet PersistenceExceptionTranslator to use to perform the translation
|
||||
* @return a translated exception if translation is possible, or
|
||||
* the raw exception if it is not
|
||||
* @return a translated persistence exception if translation is possible,
|
||||
* or the raw exception if it is not
|
||||
*/
|
||||
public static RuntimeException translateIfNecessary(
|
||||
RuntimeException rawException, PersistenceExceptionTranslator pet) {
|
||||
|
|
|
|||
Loading…
Reference in New Issue