Skip to content

Commit 8810913

Browse files
Dan Sievewrightsnicoll
Dan Sievewright
authored andcommitted
Prevent further configuration once SqlCall is compiled
This commit prevents AbstractJdbcCall to be further configured once it is compiled. See gh-33729
1 parent 83ab717 commit 8810913

File tree

2 files changed

+93
-11
lines changed

2 files changed

+93
-11
lines changed

spring-jdbc/src/main/java/org/springframework/jdbc/core/simple/AbstractJdbcCall.java

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -248,14 +248,16 @@ protected CallableStatementCreatorFactory getCallableStatementFactory() {
248248
* @param parameter the {@link SqlParameter} to add
249249
*/
250250
public void addDeclaredParameter(SqlParameter parameter) {
251-
Assert.notNull(parameter, "The supplied parameter must not be null");
252-
if (!StringUtils.hasText(parameter.getName())) {
253-
throw new InvalidDataAccessApiUsageException(
254-
"You must specify a parameter name when declaring parameters for \"" + getProcedureName() + "\"");
255-
}
256-
this.declaredParameters.add(parameter);
257-
if (logger.isDebugEnabled()) {
258-
logger.debug("Added declared parameter for [" + getProcedureName() + "]: " + parameter.getName());
251+
if(!isCompiled()) {
252+
Assert.notNull(parameter, "The supplied parameter must not be null");
253+
if (!StringUtils.hasText(parameter.getName())) {
254+
throw new InvalidDataAccessApiUsageException(
255+
"You must specify a parameter name when declaring parameters for \"" + getProcedureName() + "\"");
256+
}
257+
this.declaredParameters.add(parameter);
258+
if (logger.isDebugEnabled()) {
259+
logger.debug("Added declared parameter for [" + getProcedureName() + "]: " + parameter.getName());
260+
}
259261
}
260262
}
261263

@@ -265,9 +267,11 @@ public void addDeclaredParameter(SqlParameter parameter) {
265267
* @param rowMapper the RowMapper implementation to use
266268
*/
267269
public void addDeclaredRowMapper(String parameterName, RowMapper<?> rowMapper) {
268-
this.declaredRowMappers.put(parameterName, rowMapper);
269-
if (logger.isDebugEnabled()) {
270-
logger.debug("Added row mapper for [" + getProcedureName() + "]: " + parameterName);
270+
if(!isCompiled()) {
271+
this.declaredRowMappers.put(parameterName, rowMapper);
272+
if (logger.isDebugEnabled()) {
273+
logger.debug("Added row mapper for [" + getProcedureName() + "]: " + parameterName);
274+
}
271275
}
272276
}
273277

spring-jdbc/src/test/java/org/springframework/jdbc/core/simple/SimpleJdbcCallTests.java

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@
1616

1717
package org.springframework.jdbc.core.simple;
1818

19+
import java.lang.reflect.Field;
1920
import java.sql.CallableStatement;
2021
import java.sql.Connection;
2122
import java.sql.DatabaseMetaData;
2223
import java.sql.ResultSet;
2324
import java.sql.SQLException;
2425
import java.sql.Types;
26+
import java.util.List;
27+
import java.util.Map;
2528

2629
import javax.sql.DataSource;
2730

@@ -30,6 +33,7 @@
3033

3134
import org.springframework.dao.InvalidDataAccessApiUsageException;
3235
import org.springframework.jdbc.BadSqlGrammarException;
36+
import org.springframework.jdbc.core.RowMapper;
3337
import org.springframework.jdbc.core.SqlOutParameter;
3438
import org.springframework.jdbc.core.SqlParameter;
3539
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
@@ -360,4 +364,78 @@ void correctSybaseFunctionStatementNamed() throws Exception {
360364
verifyStatement(adder, "{call ADD_INVOICE(@AMOUNT = ?, @CUSTID = ?)}");
361365
}
362366

367+
/**
368+
* This test verifies that when declaring a parameter for a SimpleJdbcCall,
369+
* then the parameter is added as expected.
370+
*/
371+
@SuppressWarnings("unchecked")
372+
@Test
373+
void verifyUncompiledDeclareParameterIsAdded() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
374+
SimpleJdbcCall call = new SimpleJdbcCall(dataSource)
375+
.withProcedureName("procedure_name")
376+
.declareParameters(new SqlParameter("PARAM", Types.VARCHAR));
377+
378+
Field params = AbstractJdbcCall.class.getDeclaredField("declaredParameters");
379+
params.setAccessible(true);
380+
List<SqlParameter> paramList = (List<SqlParameter>) params.get(call);
381+
assertThat(paramList).hasSize(1).allMatch(sqlParam -> sqlParam.getName().equals("PARAM"));
382+
}
383+
384+
/**
385+
* This verifies that once the SimpleJdbcCall is compiled, then adding
386+
* a parameter is ignored
387+
*/
388+
@SuppressWarnings("unchecked")
389+
@Test
390+
void verifyWhenCompiledThenDeclareParameterIsIgnored() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
391+
SimpleJdbcCall call = new SimpleJdbcCall(dataSource)
392+
.withProcedureName("procedure_name")
393+
.declareParameters(new SqlParameter("PARAM", Types.VARCHAR));
394+
call.compile();
395+
396+
call.declareParameters(new SqlParameter("Ignored Param", Types.VARCHAR));
397+
398+
Field params = AbstractJdbcCall.class.getDeclaredField("declaredParameters");
399+
params.setAccessible(true);
400+
List<SqlParameter> paramList = (List<SqlParameter>) params.get(call);
401+
assertThat(paramList).hasSize(1).allMatch(sqlParam -> sqlParam.getName().equals("PARAM"));
402+
}
403+
404+
/**
405+
* When adding a declared row mapper, this verifies that the declaredRowMappers
406+
* gets the new mapper
407+
*/
408+
@SuppressWarnings("unchecked")
409+
@Test
410+
void verifyUncompiledDeclareRowMapperIsAdded() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
411+
SimpleJdbcCall call = new SimpleJdbcCall(dataSource)
412+
.withProcedureName("procedure_name")
413+
.returningResultSet("result_set", (rs,i) -> new Object());
414+
415+
Field rowMappers = AbstractJdbcCall.class.getDeclaredField("declaredRowMappers");
416+
rowMappers.setAccessible(true);
417+
Map<String, RowMapper<?>> mappers = (Map<String, RowMapper<?>>) rowMappers.get(call);
418+
assertThat(mappers).hasSize(1).allSatisfy((key,value) -> key.equals("result_set"));
419+
}
420+
421+
/**
422+
* This verifies that when adding a row mapper after the call is compiled
423+
* then the request is ignored
424+
*/
425+
@SuppressWarnings("unchecked")
426+
@Test
427+
void verifyWhenCompiledThenDeclareRowMapperIsIgnored() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
428+
SimpleJdbcCall call = new SimpleJdbcCall(dataSource)
429+
.withProcedureName("procedure_name")
430+
.returningResultSet("result_set", (rs,i) -> new Object());
431+
call.compile();
432+
433+
call.returningResultSet("not added", (rs,i) -> new Object());
434+
435+
Field rowMappers = AbstractJdbcCall.class.getDeclaredField("declaredRowMappers");
436+
rowMappers.setAccessible(true);
437+
Map<String, RowMapper<?>> mappers = (Map<String, RowMapper<?>>) rowMappers.get(call);
438+
assertThat(mappers).hasSize(1).allSatisfy((key,value) -> key.equals("result_set"));
439+
}
440+
363441
}

0 commit comments

Comments
 (0)