Skip to content

Commit a7f930d

Browse files
authored
Apply Nullability to JDBC module
Related to: spring-projects#10083 Signed-off-by: Jiandong Ma <[email protected]>
1 parent d731e1c commit a7f930d

34 files changed

+183
-102
lines changed

spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/BeanPropertySqlParameterSourceFactory.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import java.util.HashMap;
2020
import java.util.Map;
2121

22+
import org.jspecify.annotations.Nullable;
23+
2224
import org.springframework.jdbc.core.namedparam.AbstractSqlParameterSource;
2325
import org.springframework.jdbc.core.namedparam.BeanPropertySqlParameterSource;
2426
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@@ -69,7 +71,7 @@ private static final class StaticBeanPropertySqlParameterSource extends Abstract
6971
}
7072

7173
@Override
72-
public Object getValue(String paramName) throws IllegalArgumentException {
74+
public @Nullable Object getValue(String paramName) throws IllegalArgumentException {
7375
return this.staticParameters.containsKey(paramName)
7476
? this.staticParameters.get(paramName)
7577
: this.input.getValue(paramName);

spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,13 @@
2020
import java.util.HashMap;
2121
import java.util.Map;
2222

23+
import org.jspecify.annotations.Nullable;
24+
2325
import org.springframework.expression.Expression;
2426
import org.springframework.expression.ExpressionException;
2527
import org.springframework.integration.util.AbstractExpressionEvaluator;
2628
import org.springframework.jdbc.core.namedparam.AbstractSqlParameterSource;
2729
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
28-
import org.springframework.lang.Nullable;
2930
import org.springframework.util.Assert;
3031

3132
/**

spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcMessageHandler.java

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,15 @@
2424
import java.util.LinkedList;
2525
import java.util.List;
2626
import java.util.Map;
27+
import java.util.Objects;
2728
import java.util.stream.Collectors;
2829
import java.util.stream.Stream;
2930
import java.util.stream.StreamSupport;
3031

3132
import javax.sql.DataSource;
3233

34+
import org.jspecify.annotations.Nullable;
35+
3336
import org.springframework.integration.handler.AbstractMessageHandler;
3437
import org.springframework.jdbc.core.BatchPreparedStatementSetter;
3538
import org.springframework.jdbc.core.ColumnMapRowMapper;
@@ -45,7 +48,6 @@
4548
import org.springframework.jdbc.support.GeneratedKeyHolder;
4649
import org.springframework.jdbc.support.JdbcUtils;
4750
import org.springframework.jdbc.support.KeyHolder;
48-
import org.springframework.lang.Nullable;
4951
import org.springframework.messaging.Message;
5052
import org.springframework.messaging.MessageHeaders;
5153
import org.springframework.util.Assert;
@@ -89,13 +91,13 @@ public class JdbcMessageHandler extends AbstractMessageHandler {
8991

9092
private final String updateSql;
9193

92-
private PreparedStatementCreator generatedKeysStatementCreator;
94+
private @Nullable PreparedStatementCreator generatedKeysStatementCreator;
9395

94-
private SqlParameterSourceFactory sqlParameterSourceFactory;
96+
private @Nullable SqlParameterSourceFactory sqlParameterSourceFactory;
9597

9698
private boolean keysGenerated;
9799

98-
private MessagePreparedStatementSetter preparedStatementSetter;
100+
private @Nullable MessagePreparedStatementSetter preparedStatementSetter;
99101

100102
private boolean usePayloadAsParameterSource;
101103

@@ -201,13 +203,15 @@ protected void handleMessageInternal(Message<?> message) {
201203
* @param keysGenerated generate key or not.
202204
* @return a generated keys for update.
203205
*/
206+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
204207
protected List<? extends Map<String, Object>> executeUpdateQuery(final Message<?> message, boolean keysGenerated) {
208+
MessagePreparedStatementSetter preparedStatementSetterToUse = this.preparedStatementSetter;
205209
if (keysGenerated) {
206-
if (this.preparedStatementSetter != null) {
207-
return this.jdbcOperations.getJdbcOperations()
210+
if (preparedStatementSetterToUse != null) {
211+
List<Map<String, Object>> result = this.jdbcOperations.getJdbcOperations()
208212
.execute(this.generatedKeysStatementCreator,
209213
ps -> {
210-
this.preparedStatementSetter.setValues(ps, message);
214+
preparedStatementSetterToUse.setValues(ps, message);
211215
ps.executeUpdate();
212216
ResultSet keys = ps.getGeneratedKeys(); // NOSONAR closed in JdbcUtils
213217
if (keys != null) {
@@ -221,6 +225,7 @@ protected List<? extends Map<String, Object>> executeUpdateQuery(final Message<?
221225
}
222226
return new LinkedList<>();
223227
});
228+
return Objects.requireNonNull(result);
224229
}
225230
else {
226231
KeyHolder keyHolder = new GeneratedKeyHolder();
@@ -236,7 +241,7 @@ protected List<? extends Map<String, Object>> executeUpdateQuery(final Message<?
236241

237242
int[] updates;
238243

239-
if (this.preparedStatementSetter != null) {
244+
if (preparedStatementSetterToUse != null) {
240245
Message<?>[] messages =
241246
payloadStream
242247
.map(payload -> payloadToMessage(payload, message.getHeaders()))
@@ -247,7 +252,7 @@ protected List<? extends Map<String, Object>> executeUpdateQuery(final Message<?
247252

248253
@Override
249254
public void setValues(PreparedStatement ps, int i) throws SQLException {
250-
JdbcMessageHandler.this.preparedStatementSetter.setValues(ps, messages[i]);
255+
preparedStatementSetterToUse.setValues(ps, messages[i]);
251256
}
252257

253258
@Override
@@ -264,7 +269,7 @@ public int getBatchSize() {
264269
this.usePayloadAsParameterSource
265270
? payload :
266271
payloadToMessage(payload, message.getHeaders()))
267-
.map(this.sqlParameterSourceFactory::createParameterSource)
272+
.map(Objects.requireNonNull(this.sqlParameterSourceFactory)::createParameterSource)
268273
.toArray(SqlParameterSource[]::new);
269274

270275
updates = this.jdbcOperations.batchUpdate(this.updateSql, sqlParameterSources);
@@ -281,9 +286,9 @@ public int getBatchSize() {
281286
else {
282287
int updated;
283288

284-
if (this.preparedStatementSetter != null) {
289+
if (preparedStatementSetterToUse != null) {
285290
updated = this.jdbcOperations.getJdbcOperations()
286-
.update(this.updateSql, ps -> this.preparedStatementSetter.setValues(ps, message));
291+
.update(this.updateSql, ps -> preparedStatementSetterToUse.setValues(ps, message));
287292
}
288293
else {
289294
Object parameterSource = this.usePayloadAsParameterSource ? message.getPayload() : message;

spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcOutboundGateway.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121

2222
import javax.sql.DataSource;
2323

24+
import org.jspecify.annotations.Nullable;
25+
2426
import org.springframework.beans.factory.BeanFactory;
2527
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
2628
import org.springframework.jdbc.core.JdbcOperations;
@@ -41,17 +43,17 @@
4143
*/
4244
public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler {
4345

44-
private final JdbcMessageHandler handler;
46+
private final @Nullable JdbcMessageHandler handler;
4547

46-
private final JdbcPollingChannelAdapter poller;
48+
private final @Nullable JdbcPollingChannelAdapter poller;
4749

4850
private SqlParameterSourceFactory sqlParameterSourceFactory = new ExpressionEvaluatingSqlParameterSourceFactory();
4951

5052
private boolean sqlParameterSourceFactorySet;
5153

5254
private boolean keysGenerated;
5355

54-
private Integer maxRows;
56+
private @Nullable Integer maxRows;
5557

5658
/**
5759
* Construct an instance based on the provided {@link DataSource} and update SQL.
@@ -87,7 +89,7 @@ public JdbcOutboundGateway(JdbcOperations jdbcOperations, String updateQuery) {
8789
* @param updateQuery the update to execute.
8890
* @param selectQuery the select to execute.
8991
*/
90-
public JdbcOutboundGateway(JdbcOperations jdbcOperations, String updateQuery, String selectQuery) {
92+
public JdbcOutboundGateway(JdbcOperations jdbcOperations, String updateQuery, @Nullable String selectQuery) {
9193
Assert.notNull(jdbcOperations, "'jdbcOperations' must not be null.");
9294

9395
if (!StringUtils.hasText(updateQuery) && !StringUtils.hasText(selectQuery)) {
@@ -172,6 +174,7 @@ public void setReplySqlParameterSourceFactory(SqlParameterSourceFactory sqlParam
172174
* @param rowMapper the {@link RowMapper} to use.
173175
*/
174176
public void setRowMapper(RowMapper<?> rowMapper) {
177+
Assert.notNull(this.poller, "'poller' must not be null");
175178
this.poller.setRowMapper(rowMapper);
176179
}
177180

@@ -183,7 +186,7 @@ public String getComponentType() {
183186
@Override
184187
protected void doInit() {
185188
if (this.maxRows != null) {
186-
Assert.notNull(this.poller, "If you want to set 'maxRows', then you must provide a 'selectQuery'.");
189+
Assert.notNull(this.poller, "'poller' must not be null when 'maxRows' is not null");
187190
this.poller.setMaxRows(this.maxRows);
188191
}
189192

spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/JdbcPollingChannelAdapter.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@
2020
import java.sql.PreparedStatement;
2121
import java.sql.SQLException;
2222
import java.util.List;
23+
import java.util.Objects;
2324
import java.util.function.Consumer;
2425

2526
import javax.sql.DataSource;
2627

28+
import org.jspecify.annotations.Nullable;
29+
2730
import org.springframework.beans.factory.BeanFactory;
2831
import org.springframework.integration.endpoint.AbstractMessageSource;
2932
import org.springframework.jdbc.core.ColumnMapRowMapper;
@@ -38,7 +41,6 @@
3841
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
3942
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
4043
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
41-
import org.springframework.lang.Nullable;
4244
import org.springframework.util.Assert;
4345

4446
/**
@@ -56,9 +58,10 @@ public class JdbcPollingChannelAdapter extends AbstractMessageSource<Object> {
5658

5759
private final NamedParameterJdbcOperations jdbcOperations;
5860

61+
@SuppressWarnings("NullAway.Init")
5962
private RowMapper<?> rowMapper;
6063

61-
private SqlParameterSource sqlQueryParameterSource;
64+
private @Nullable SqlParameterSource sqlQueryParameterSource;
6265

6366
private boolean updatePerRow = false;
6467

@@ -70,7 +73,7 @@ public class JdbcPollingChannelAdapter extends AbstractMessageSource<Object> {
7073

7174
private volatile String selectQuery;
7275

73-
private volatile String updateSql;
76+
private volatile @Nullable String updateSql;
7477

7578
/**
7679
* Constructor taking {@link DataSource} from which the DB Connection can be
@@ -113,10 +116,7 @@ protected PreparedStatementCreator getPreparedStatementCreator(String sql,
113116
* @param rowMapper the {@link RowMapper} to use.
114117
*/
115118
public void setRowMapper(@Nullable RowMapper<?> rowMapper) {
116-
this.rowMapper = rowMapper;
117-
if (rowMapper == null) {
118-
this.rowMapper = new ColumnMapRowMapper();
119-
}
119+
this.rowMapper = Objects.requireNonNullElseGet(rowMapper, ColumnMapRowMapper::new);
120120
}
121121

122122
/**
@@ -192,9 +192,9 @@ public String getComponentType() {
192192
* mapped results are returned.
193193
*/
194194
@Override
195-
protected Object doReceive() {
195+
protected @Nullable Object doReceive() {
196196
List<?> payload = doPoll(this.sqlQueryParameterSource);
197-
if (payload.size() < 1) {
197+
if (payload.isEmpty()) {
198198
payload = null;
199199
}
200200
if (payload != null && this.updateSql != null) {
@@ -224,6 +224,7 @@ protected List<?> doPoll(@Nullable SqlParameterSource sqlQueryParameterSource) {
224224
}
225225
}
226226

227+
@SuppressWarnings("NullAway") // Dataflow analysis limitation
227228
private void executeUpdateQuery(Object obj) {
228229
this.jdbcOperations.update(this.updateSql, this.sqlParameterSourceFactory.createParameterSource(obj));
229230
}
@@ -239,7 +240,7 @@ public PreparedStatement createPreparedStatement(Connection con) throws SQLExcep
239240
}
240241

241242
@Override
242-
public String getSql() {
243+
public @Nullable String getSql() {
243244
if (this.delegate instanceof SqlProvider) {
244245
return ((SqlProvider) this.delegate).getSql();
245246
}

spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/StoredProcExecutor.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828

2929
import javax.sql.DataSource;
3030

31+
import org.jspecify.annotations.Nullable;
32+
3133
import org.springframework.beans.factory.BeanFactory;
3234
import org.springframework.beans.factory.BeanFactoryAware;
3335
import org.springframework.beans.factory.InitializingBean;
@@ -41,7 +43,6 @@
4143
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
4244
import org.springframework.jdbc.core.simple.SimpleJdbcCall;
4345
import org.springframework.jdbc.core.simple.SimpleJdbcCallOperations;
44-
import org.springframework.lang.Nullable;
4546
import org.springframework.messaging.Message;
4647
import org.springframework.util.Assert;
4748

@@ -69,14 +70,18 @@ public class StoredProcExecutor implements BeanFactoryAware, InitializingBean {
6970

7071
private Map<String, RowMapper<?>> returningResultSetRowMappers = new HashMap<>(0);
7172

73+
@SuppressWarnings("NullAway.Init")
7274
private EvaluationContext evaluationContext;
7375

76+
@SuppressWarnings("NullAway.Init")
7477
private BeanFactory beanFactory;
7578

7679
private int jdbcCallOperationsCacheSize = DEFAULT_CACHE_SIZE;
7780

81+
@SuppressWarnings("NullAway.Init")
7882
private Map<String, SimpleJdbcCallOperations> jdbcCallOperationsMap;
7983

84+
@SuppressWarnings("NullAway.Init")
8085
private Expression storedProcedureNameExpression;
8186

8287
/**
@@ -112,20 +117,22 @@ public class StoredProcExecutor implements BeanFactoryAware, InitializingBean {
112117
* This may be sufficient for basic use cases. For more sophisticated options
113118
* consider passing in one or more {@link ProcedureParameter}.
114119
*/
120+
@SuppressWarnings("NullAway.Init")
115121
private SqlParameterSourceFactory sqlParameterSourceFactory;
116122

117123
/**
118124
* Indicates that whether only the payload of the passed-in {@link Message}
119125
* shall be used as a source of parameters.
120126
* @see #setUsePayloadAsParameterSource(boolean)
121127
*/
128+
@SuppressWarnings("NullAway.Init")
122129
private Boolean usePayloadAsParameterSource;
123130

124131
/**
125132
* Custom Stored Procedure parameters that may contain static values
126133
* or Strings representing an {@link Expression}.
127134
*/
128-
private List<ProcedureParameter> procedureParameters;
135+
private @Nullable List<ProcedureParameter> procedureParameters;
129136

130137
private boolean isFunction = false;
131138

@@ -241,7 +248,7 @@ private SimpleJdbcCall createSimpleJdbcCall(String storedProcedureName) {
241248
* available to extract {@link ProcedureParameter} values from it.
242249
* @return Map containing the stored procedure results if any.
243250
*/
244-
public Map<String, Object> executeStoredProcedure() {
251+
public Map<String, @Nullable Object> executeStoredProcedure() {
245252
return executeStoredProcedureInternal(new Object(), evaluateExpression(null));
246253
}
247254

@@ -251,7 +258,7 @@ public Map<String, Object> executeStoredProcedure() {
251258
* @param message A message.
252259
* @return Map containing the stored procedure results if any.
253260
*/
254-
public Map<String, Object> executeStoredProcedure(Message<?> message) {
261+
public Map<String, @Nullable Object> executeStoredProcedure(Message<?> message) {
255262
Assert.notNull(message, "The message parameter must not be null.");
256263
Assert.notNull(this.usePayloadAsParameterSource, "Property usePayloadAsParameterSource "
257264
+ "was Null. Did you call afterPropertiesSet()?");
@@ -286,7 +293,7 @@ private String evaluateExpression(@Nullable Message<?> message) {
286293
* @param input The message is used to extract parameters for the stored procedure.
287294
* @return A map containing the return values from the Stored Procedure call if any.
288295
*/
289-
private Map<String, Object> executeStoredProcedureInternal(Object input, String storedProcedureName) {
296+
private Map<String, @Nullable Object> executeStoredProcedureInternal(Object input, String storedProcedureName) {
290297
Assert.notNull(this.sqlParameterSourceFactory, "Property sqlParameterSourceFactory "
291298
+ "was Null. Did you call afterPropertiesSet()?");
292299

@@ -368,15 +375,15 @@ public void setSqlParameterSourceFactory(SqlParameterSourceFactory sqlParameterS
368375
/**
369376
* @return the name of the Stored Procedure or Function if set. Null otherwise.
370377
* */
371-
public String getStoredProcedureName() {
378+
public @Nullable String getStoredProcedureName() {
372379
return this.storedProcedureNameExpression instanceof LiteralExpression ?
373380
this.storedProcedureNameExpression.getValue(String.class) : null;
374381
}
375382

376383
/**
377384
* @return the Stored Procedure Name Expression as a String if set. Null otherwise.
378385
* */
379-
public String getStoredProcedureNameExpressionAsString() {
386+
public @Nullable String getStoredProcedureNameExpressionAsString() {
380387
return this.storedProcedureNameExpression != null
381388
? this.storedProcedureNameExpression.getExpressionString()
382389
: null;

0 commit comments

Comments
 (0)