diff --git a/gradle/spring-module.gradle b/gradle/spring-module.gradle index a899900abf5..fbece5148fc 100644 --- a/gradle/spring-module.gradle +++ b/gradle/spring-module.gradle @@ -119,3 +119,6 @@ publishing { components.java.withVariantsFromConfiguration(configurations.testFixturesApiElements) { skip() } components.java.withVariantsFromConfiguration(configurations.testFixturesRuntimeElements) { skip() } +nullability { + nullAwayVersion = "0.12.10" +} diff --git a/spring-core/src/main/java/org/springframework/util/function/SingletonSupplier.java b/spring-core/src/main/java/org/springframework/util/function/SingletonSupplier.java index 5b53f023b6a..865cc6888a5 100644 --- a/spring-core/src/main/java/org/springframework/util/function/SingletonSupplier.java +++ b/spring-core/src/main/java/org/springframework/util/function/SingletonSupplier.java @@ -39,7 +39,7 @@ import org.springframework.util.Assert; * @since 5.1 * @param the type of results supplied by this supplier */ -public class SingletonSupplier implements Supplier<@Nullable T> { +public class SingletonSupplier implements Supplier { private final @Nullable Supplier instanceSupplier; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java index 096d397cd37..da05923cae2 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/JdbcTemplate.java @@ -441,7 +441,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public void execute(String sql) throws DataAccessException { if (logger.isDebugEnabled()) { logger.debug("Executing SQL statement [" + sql + "]"); @@ -464,7 +463,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public T query(String sql, ResultSetExtractor rse) throws DataAccessException { Assert.notNull(sql, "SQL must not be null"); Assert.notNull(rse, "ResultSetExtractor must not be null"); @@ -475,7 +473,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { // Callback to execute the query. class QueryStatementCallback implements StatementCallback, SqlProvider { @Override - public @Nullable T doInStatement(Statement stmt) throws SQLException { + public T doInStatement(Statement stmt) throws SQLException { ResultSet rs = null; try { rs = stmt.executeQuery(sql); @@ -495,7 +493,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public void query(String sql, RowCallbackHandler rch) throws DataAccessException { query(sql, new RowCallbackHandlerResultSetExtractor(rch, this.maxRows)); } @@ -544,7 +541,6 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public List<@Nullable T> queryForList(String sql, Class elementType) throws DataAccessException { return query(sql, getSingleColumnRowMapper(elementType)); } @@ -725,7 +721,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 */ - public @Nullable T query( + public T query( PreparedStatementCreator psc, @Nullable PreparedStatementSetter pss, ResultSetExtractor rse) throws DataAccessException { @@ -751,13 +747,11 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public T query(PreparedStatementCreator psc, ResultSetExtractor rse) throws DataAccessException { return query(psc, null, rse); } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public T query(String sql, @Nullable PreparedStatementSetter pss, ResultSetExtractor rse) throws DataAccessException { return query(new SimplePreparedStatementCreator(sql), pss, rse); } @@ -779,13 +773,11 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public void query(PreparedStatementCreator psc, RowCallbackHandler rch) throws DataAccessException { query(psc, new RowCallbackHandlerResultSetExtractor(rch, this.maxRows)); } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public void query(String sql, @Nullable PreparedStatementSetter pss, RowCallbackHandler rch) throws DataAccessException { query(sql, pss, new RowCallbackHandlerResultSetExtractor(rch, this.maxRows)); } @@ -930,20 +922,17 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public List<@Nullable T> queryForList(String sql, @Nullable Object @Nullable [] args, int[] argTypes, Class elementType) throws DataAccessException { return query(sql, args, argTypes, getSingleColumnRowMapper(elementType)); } @Deprecated(since = "5.3") @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public List<@Nullable T> queryForList(String sql, @Nullable Object @Nullable [] args, Class elementType) throws DataAccessException { return query(sql, newArgPreparedStatementSetter(args), getSingleColumnRowMapper(elementType)); } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public List<@Nullable T> queryForList(String sql, Class elementType, @Nullable Object @Nullable ... args) throws DataAccessException { return query(sql, newArgPreparedStatementSetter(args), getSingleColumnRowMapper(elementType)); } @@ -1413,7 +1402,7 @@ public class JdbcTemplate extends JdbcAccessor implements JdbcOperations { * @return the RowMapper to use * @see SingleColumnRowMapper */ - protected RowMapper getSingleColumnRowMapper(Class requiredType) { + protected RowMapper<@Nullable T> getSingleColumnRowMapper(Class requiredType) { return new SingleColumnRowMapper<>(requiredType); } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/RowMapperResultSetExtractor.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/RowMapperResultSetExtractor.java index 837139ae274..fbeac97dcb9 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/RowMapperResultSetExtractor.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/RowMapperResultSetExtractor.java @@ -21,8 +21,6 @@ import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -import org.jspecify.annotations.Nullable; - import org.springframework.util.Assert; /** @@ -61,7 +59,7 @@ import org.springframework.util.Assert; * @see JdbcTemplate * @see org.springframework.jdbc.object.MappingSqlQuery */ -public class RowMapperResultSetExtractor implements ResultSetExtractor> { +public class RowMapperResultSetExtractor implements ResultSetExtractor> { private final RowMapper rowMapper; diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java index fd7ae1996c6..db76fa820de 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/namedparam/NamedParameterJdbcTemplate.java @@ -294,7 +294,6 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public List<@Nullable T> queryForList(String sql, SqlParameterSource paramSource, Class elementType) throws DataAccessException { @@ -302,7 +301,6 @@ public class NamedParameterJdbcTemplate implements NamedParameterJdbcOperations } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public List<@Nullable T> queryForList(String sql, Map paramMap, Class elementType) throws DataAccessException { diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java index 485f2959a7d..56775367231 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcInsert.java @@ -448,7 +448,6 @@ public abstract class AbstractJdbcInsert { /** * Delegate method to execute the insert, generating any number of keys. */ - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 private KeyHolder executeInsertAndReturnKeyHolderInternal(List values) { if (logger.isDebugEnabled()) { logger.debug("The following parameters are used for call " + getInsertString() + " with: " + values); diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/DefaultJdbcClient.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/DefaultJdbcClient.java index c378c4e606f..6f8d5b8f86a 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/DefaultJdbcClient.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/DefaultJdbcClient.java @@ -240,7 +240,7 @@ final class DefaultJdbcClient implements JdbcClient { } @Override - @SuppressWarnings({"unchecked", "NullAway"}) // See https://github.com/uber/NullAway/issues/1075 + @SuppressWarnings("unchecked") public MappedQuerySpec<@Nullable T> query(Class mappedClass) { RowMapper rowMapper = rowMapperCache.computeIfAbsent(mappedClass, key -> BeanUtils.isSimpleProperty(mappedClass) ? @@ -342,7 +342,6 @@ final class DefaultJdbcClient implements JdbcClient { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public List<@Nullable Object> singleColumn() { return classicOps.queryForList(sql, Object.class, indexedParams.toArray()); } @@ -362,13 +361,11 @@ final class DefaultJdbcClient implements JdbcClient { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public Map singleRow() { return namedParamOps.queryForMap(sql, namedParamSource); } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 public List<@Nullable Object> singleColumn() { return namedParamOps.queryForList(sql, namedParamSource, Object.class); } diff --git a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/JdbcClient.java b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/JdbcClient.java index e98b421bf2b..e67dfada113 100644 --- a/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/JdbcClient.java +++ b/spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/JdbcClient.java @@ -391,7 +391,6 @@ public interface JdbcClient { * @see #optionalValue() * @see DataAccessUtils#requiredSingleResult(Collection) */ - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 default Object singleValue() { return DataAccessUtils.requiredSingleResult(singleColumn()); } @@ -403,7 +402,6 @@ public interface JdbcClient { * @see #singleValue() * @see DataAccessUtils#optionalResult(Collection) */ - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 default Optional optionalValue() { return DataAccessUtils.optionalResult(singleColumn()); } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java index 78e287b4248..e9d4a5fa323 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/DefaultWebTestClient.java @@ -596,7 +596,6 @@ class DefaultWebTestClient implements WebTestClient { } @Override - @SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1129 public T value(Consumer<@Nullable B> consumer) { this.result.assertWithDiagnostics(() -> consumer.accept(this.result.getResponseBody())); return self(); @@ -620,7 +619,7 @@ class DefaultWebTestClient implements WebTestClient { } - private static class DefaultListBodySpec extends DefaultBodySpec, ListBodySpec> + private static class DefaultListBodySpec extends DefaultBodySpec, ListBodySpec> implements ListBodySpec { DefaultListBodySpec(EntityExchangeResult> result) { @@ -629,7 +628,7 @@ class DefaultWebTestClient implements WebTestClient { @Override public ListBodySpec hasSize(int size) { - List<@Nullable E> actual = getResult().getResponseBody(); + List actual = getResult().getResponseBody(); String message = "Response body does not contain " + size + " elements"; getResult().assertWithDiagnostics(() -> AssertionErrors.assertEquals(message, size, (actual != null ? actual.size() : 0))); @@ -638,9 +637,9 @@ class DefaultWebTestClient implements WebTestClient { @Override @SuppressWarnings("unchecked") - public ListBodySpec contains(@Nullable E... elements) { + public ListBodySpec contains(E... elements) { List expected = Arrays.asList(elements); - List<@Nullable E> actual = getResult().getResponseBody(); + List actual = getResult().getResponseBody(); String message = "Response body does not contain " + expected; getResult().assertWithDiagnostics(() -> AssertionErrors.assertTrue(message, (actual != null && actual.containsAll(expected)))); @@ -649,9 +648,9 @@ class DefaultWebTestClient implements WebTestClient { @Override @SuppressWarnings("unchecked") - public ListBodySpec doesNotContain(@Nullable E... elements) { + public ListBodySpec doesNotContain(E... elements) { List expected = Arrays.asList(elements); - List<@Nullable E> actual = getResult().getResponseBody(); + List actual = getResult().getResponseBody(); String message = "Response body should not have contained " + expected; getResult().assertWithDiagnostics(() -> AssertionErrors.assertTrue(message, (actual == null || !actual.containsAll(expected)))); @@ -659,7 +658,7 @@ class DefaultWebTestClient implements WebTestClient { } @Override - public EntityExchangeResult> returnResult() { + public EntityExchangeResult> returnResult() { return getResult(); } } diff --git a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java index 17a98ebed23..f8c896493a0 100644 --- a/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/reactive/server/WebTestClient.java @@ -975,7 +975,7 @@ public interface WebTestClient { * * @param the body list element type */ - interface ListBodySpec extends BodySpec, ListBodySpec> { + interface ListBodySpec extends BodySpec, ListBodySpec> { /** * Assert the extracted list of values is of the given size. @@ -988,14 +988,14 @@ public interface WebTestClient { * @param elements the elements to check */ @SuppressWarnings("unchecked") - ListBodySpec contains(@Nullable E... elements); + ListBodySpec contains(E... elements); /** * Assert the extracted list of values doesn't contain the given elements. * @param elements the elements to check */ @SuppressWarnings("unchecked") - ListBodySpec doesNotContain(@Nullable E... elements); + ListBodySpec doesNotContain(E... elements); } diff --git a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java index c6ee841720e..900bd402f0b 100644 --- a/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java +++ b/spring-test/src/main/java/org/springframework/test/web/servlet/client/DefaultRestTestClient.java @@ -367,7 +367,6 @@ class DefaultRestTestClient implements RestTestClient { } @Override - @SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1129 public T value(Function<@Nullable B, @Nullable R> bodyMapper, Matcher matcher) { this.result.assertWithDiagnostics(() -> { B body = this.result.getResponseBody(); @@ -377,7 +376,6 @@ class DefaultRestTestClient implements RestTestClient { } @Override - @SuppressWarnings("NullAway") // https://github.com/uber/NullAway/issues/1129 public T value(Consumer<@Nullable B> consumer) { this.result.assertWithDiagnostics(() -> consumer.accept(this.result.getResponseBody())); return self(); diff --git a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java index 58309754b55..a6b1b56e525 100644 --- a/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java +++ b/spring-tx/src/main/java/org/springframework/dao/support/DataAccessUtils.java @@ -116,7 +116,7 @@ public abstract class DataAccessUtils { * element has been found in the given Collection * @since 6.1 */ - public static Optional<@NonNull T> optionalResult(@Nullable Collection results) + public static Optional optionalResult(@Nullable Collection results) throws IncorrectResultSizeDataAccessException { return Optional.ofNullable(singleResult(results)); diff --git a/spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java b/spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java index 600bafe9aa0..bdc292be0ab 100644 --- a/spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java +++ b/spring-web/src/main/java/org/springframework/web/client/DefaultRestClient.java @@ -803,13 +803,13 @@ final class DefaultRestClient implements RestClient { } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 + @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1290 public @Nullable T body(Class bodyType) { return executeAndExtract((request, response) -> readBody(request, response, bodyType, bodyType, this.hints)); } @Override - @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1075 + @SuppressWarnings("NullAway") // See https://github.com/uber/NullAway/issues/1290 public @Nullable T body(ParameterizedTypeReference bodyType) { Type type = bodyType.getType(); Class bodyClass = bodyClass(type); diff --git a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java index fa910868172..503d473f94e 100644 --- a/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java +++ b/spring-webflux/src/main/java/org/springframework/web/reactive/result/method/annotation/RequestMappingHandlerMapping.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Stream; @@ -340,14 +341,14 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi * Resolve placeholder values in the given array of patterns. * @return a new array with updated patterns */ - protected @Nullable String[] resolveEmbeddedValuesInPatterns(String[] patterns) { + protected String[] resolveEmbeddedValuesInPatterns(String[] patterns) { if (this.embeddedValueResolver == null) { return patterns; } else { - @Nullable String[] resolvedPatterns = new String[patterns.length]; + String[] resolvedPatterns = new String[patterns.length]; for (int i = 0; i < patterns.length; i++) { - resolvedPatterns[i] = this.embeddedValueResolver.resolveStringValue(patterns[i]); + resolvedPatterns[i] = Objects.requireNonNull(this.embeddedValueResolver.resolveStringValue(patterns[i])); } return resolvedPatterns; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java index 2cc4f4676e3..1ef162b6799 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMapping.java @@ -23,6 +23,7 @@ import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.function.Predicate; import java.util.stream.Stream; @@ -367,14 +368,14 @@ public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMappi * Resolve placeholder values in the given array of patterns. * @return a new array with updated patterns */ - protected @Nullable String[] resolveEmbeddedValuesInPatterns(String[] patterns) { + protected String[] resolveEmbeddedValuesInPatterns(String[] patterns) { if (this.embeddedValueResolver == null) { return patterns; } else { - @Nullable String[] resolvedPatterns = new String[patterns.length]; + String[] resolvedPatterns = new String[patterns.length]; for (int i = 0; i < patterns.length; i++) { - resolvedPatterns[i] = this.embeddedValueResolver.resolveStringValue(patterns[i]); + resolvedPatterns[i] = Objects.requireNonNull(this.embeddedValueResolver.resolveStringValue(patterns[i])); } return resolvedPatterns; }