Switch to JSpecify annotations
This commit updates the whole Spring Framework codebase to use JSpecify annotations instead of Spring null-safety annotations with JSR 305 semantics. JSpecify provides signficant enhancements such as properly defined specifications, a canonical dependency with no split-package issue, better tooling, better Kotlin integration and the capability to specify generic type, array and varargs element null-safety. Generic type null-safety is not defined by this commit yet and will be specified later. A key difference is that Spring null-safety annotations, following JSR 305 semantics, apply to fields, parameters and return values, while JSpecify annotations apply to type usages. That's why this commit moves nullability annotations closer to the type for fields and return values. See gh-28797
This commit is contained in:
@@ -18,6 +18,7 @@ package org.springframework.jdbc.config;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.PropertyValue;
|
||||
@@ -33,7 +34,6 @@ import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.datasource.AbstractDriverBasedDataSource;
|
||||
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean;
|
||||
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
@@ -188,8 +188,7 @@ class JdbcNamespaceIntegrationTests {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private String extractDataSourceUrl(String file) {
|
||||
private @Nullable String extractDataSourceUrl(String file) {
|
||||
try (ConfigurableApplicationContext context = context(file)) {
|
||||
DataSource dataSource = context.getBean(DataSource.class);
|
||||
assertNumRowsInTestTable(new JdbcTemplate(dataSource), 1);
|
||||
|
||||
@@ -24,11 +24,11 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.function.IntFunction;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.InOrder;
|
||||
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.function.ThrowingBiFunction;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
@@ -20,13 +20,13 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.assertj.core.util.Strings;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.CsvSource;
|
||||
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.core.io.support.EncodedResource;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.springframework.jdbc.datasource.init.ScriptUtils.DEFAULT_BLOCK_COMMENT_END_DELIMITER;
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.util.Map;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -36,7 +37,6 @@ import org.springframework.dao.IncorrectResultSizeDataAccessException;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.jdbc.Customer;
|
||||
import org.springframework.jdbc.core.SqlParameter;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -108,7 +108,7 @@ class SqlQueryTests {
|
||||
|
||||
SqlQuery<Integer> query = new MappingSqlQueryWithParameters<>() {
|
||||
@Override
|
||||
protected Integer mapRow(ResultSet rs, int rownum, @Nullable Object[] params, @Nullable Map<? ,?> context)
|
||||
protected Integer mapRow(ResultSet rs, int rownum, Object @Nullable [] params, @Nullable Map<? ,?> context)
|
||||
throws SQLException {
|
||||
assertThat(params).as("params were null").isNull();
|
||||
assertThat(context).as("context was null").isNull();
|
||||
|
||||
@@ -18,9 +18,10 @@ package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* Custom SQLException translation for testing.
|
||||
|
||||
@@ -24,6 +24,7 @@ import java.sql.SQLException;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
@@ -33,7 +34,6 @@ import org.springframework.dao.DataIntegrityViolationException;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.jdbc.InvalidResultSetAccessException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
@@ -139,8 +139,7 @@ class SQLErrorCodeSQLExceptionTranslatorTests {
|
||||
translator = new SQLErrorCodeSQLExceptionTranslator() {
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
@Nullable
|
||||
protected DataAccessException customTranslate(String task, @Nullable String sql, SQLException sqlException) {
|
||||
protected @Nullable DataAccessException customTranslate(String task, @Nullable String sql, SQLException sqlException) {
|
||||
assertThat(task).isEqualTo(TASK);
|
||||
assertThat(sql).isEqualTo(SQL);
|
||||
return (sqlException == badSqlEx) ? customDex : null;
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.jdbc.support;
|
||||
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.dao.CannotAcquireLockException;
|
||||
@@ -28,7 +29,6 @@ import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.dao.PessimisticLockingFailureException;
|
||||
import org.springframework.dao.TransientDataAccessResourceException;
|
||||
import org.springframework.jdbc.BadSqlGrammarException;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
@@ -16,13 +16,13 @@
|
||||
|
||||
package org.springframework.jdbc.core
|
||||
|
||||
import java.sql.*
|
||||
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.assertj.core.api.Assertions.assertThat
|
||||
import org.junit.jupiter.api.Test
|
||||
import java.sql.JDBCType
|
||||
import java.sql.ResultSet
|
||||
|
||||
/**
|
||||
* Mock object based tests for [JdbcOperations] Kotlin extensions
|
||||
@@ -54,7 +54,7 @@ class JdbcOperationsExtensionsTests {
|
||||
fun `queryForObject with nullable RowMapper-like function`() {
|
||||
every { template.queryForObject(sql, any<RowMapper<Int>>(), 3) } returns null
|
||||
assertThat(template.queryForObject<Int?>(sql, 3) { _, _ -> null }).isNull()
|
||||
verify { template.queryForObject(eq(sql), any<RowMapper<Int?>>(), eq(3)) }
|
||||
verify { template.queryForObject(eq(sql), any<RowMapper<Int>>(), eq(3)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -115,9 +115,9 @@ class JdbcOperationsExtensionsTests {
|
||||
|
||||
@Test // gh-22682
|
||||
fun `query with nullable ResultSetExtractor-like function`() {
|
||||
every { template.query(eq(sql), any<ResultSetExtractor<Int?>>(), eq(3)) } returns null
|
||||
every { template.query(eq(sql), any<ResultSetExtractor<Int>>(), eq(3)) } returns null
|
||||
assertThat(template.query<Int?>(sql, 3) { _ -> null }).isNull()
|
||||
verify { template.query(eq(sql), any<ResultSetExtractor<Int?>>(), eq(3)) }
|
||||
verify { template.query(eq(sql), any<ResultSetExtractor<Int>>(), eq(3)) }
|
||||
}
|
||||
|
||||
@Suppress("RemoveExplicitTypeArguments")
|
||||
|
||||
Reference in New Issue
Block a user