Add NPE test for ExprEvalSqlParameterSourceFactory

Related to https://github.com/spring-projects/spring-integration/issues/3113

Also clean up code style in the `ExpressionEvaluatingSqlParameterSourceFactory`
This commit is contained in:
Artem Bilan
2019-11-21 12:11:30 -05:00
parent 9fb2e570c9
commit 2da7ae016d
2 changed files with 78 additions and 61 deletions

View File

@@ -22,11 +22,10 @@ import java.util.Map;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionException; import org.springframework.expression.ExpressionException;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.integration.util.AbstractExpressionEvaluator; import org.springframework.integration.util.AbstractExpressionEvaluator;
import org.springframework.jdbc.core.namedparam.AbstractSqlParameterSource; import org.springframework.jdbc.core.namedparam.AbstractSqlParameterSource;
import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSource;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
@@ -45,8 +44,6 @@ import org.springframework.util.Assert;
public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpressionEvaluator public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpressionEvaluator
implements SqlParameterSourceFactory { implements SqlParameterSourceFactory {
private static final ExpressionParser PARSER = new SpelExpressionParser();
private static final Object ERROR = new Object(); private static final Object ERROR = new Object();
private final Map<String, Object> staticParameters = new HashMap<>(); private final Map<String, Object> staticParameters = new HashMap<>();
@@ -117,8 +114,8 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
String key = entry.getKey(); String key = entry.getKey();
String expression = entry.getValue(); String expression = entry.getValue();
Expression[] expressions = new Expression[] { Expression[] expressions = new Expression[] {
PARSER.parseExpression(expression), EXPRESSION_PARSER.parseExpression(expression),
PARSER.parseExpression("#root.![" + expression + "]") EXPRESSION_PARSER.parseExpression("#root.![" + expression + "]")
}; };
paramExpressions.put(key, expressions); paramExpressions.put(key, expressions);
} }
@@ -172,6 +169,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
ExpressionEvaluatingSqlParameterSource(Object input, Map<String, ?> staticParameters, ExpressionEvaluatingSqlParameterSource(Object input, Map<String, ?> staticParameters,
Map<String, Expression[]> parameterExpressions, boolean cache) { Map<String, Expression[]> parameterExpressions, boolean cache) {
this.input = input; this.input = input;
this.parameterExpressions = parameterExpressions; this.parameterExpressions = parameterExpressions;
this.values.putAll(staticParameters); this.values.putAll(staticParameters);
@@ -182,10 +180,12 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
} }
@Override @Override
@Nullable
public Object getValue(String paramName) throws IllegalArgumentException { public Object getValue(String paramName) throws IllegalArgumentException {
return this.doGetValue(paramName, false); return doGetValue(paramName, false);
} }
@Nullable
public Object doGetValue(String paramName, boolean calledFromHasValue) throws IllegalArgumentException { public Object doGetValue(String paramName, boolean calledFromHasValue) throws IllegalArgumentException {
if (this.values.containsKey(paramName)) { if (this.values.containsKey(paramName)) {
Object cachedByHasValue = this.values.get(paramName); Object cachedByHasValue = this.values.get(paramName);
@@ -197,14 +197,14 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
if (!this.parameterExpressions.containsKey(paramName)) { if (!this.parameterExpressions.containsKey(paramName)) {
Expression[] expressions = new Expression[] { Expression[] expressions = new Expression[] {
PARSER.parseExpression(paramName), EXPRESSION_PARSER.parseExpression(paramName),
PARSER.parseExpression("#root.![" + paramName + "]") EXPRESSION_PARSER.parseExpression("#root.![" + paramName + "]")
}; };
ExpressionEvaluatingSqlParameterSourceFactory.this.parameterExpressions.put(paramName, expressions); ExpressionEvaluatingSqlParameterSourceFactory.this.parameterExpressions.put(paramName, expressions);
this.parameterExpressions.put(paramName, expressions); this.parameterExpressions.put(paramName, expressions);
} }
Expression expression = null; Expression expression;
if (this.input instanceof Collection<?>) { if (this.input instanceof Collection<?>) {
expression = this.parameterExpressions.get(paramName)[1]; expression = this.parameterExpressions.get(paramName)[1];

View File

@@ -23,7 +23,7 @@ import java.sql.Types;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import org.junit.Test; import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactory;
import org.springframework.jdbc.core.namedparam.SqlParameterSource; import org.springframework.jdbc.core.namedparam.SqlParameterSource;
@@ -32,39 +32,41 @@ import org.springframework.jdbc.support.JdbcUtils;
/** /**
* @author Dave Syer * @author Dave Syer
* @author Meherzad Lahewala * @author Meherzad Lahewala
* @author Artem Bilan
*/ */
public class ExpressionEvaluatingSqlParameterSourceFactoryTests { class ExpressionEvaluatingSqlParameterSourceFactoryTests {
private final ExpressionEvaluatingSqlParameterSourceFactory factory = private final ExpressionEvaluatingSqlParameterSourceFactory factory =
new ExpressionEvaluatingSqlParameterSourceFactory(); new ExpressionEvaluatingSqlParameterSourceFactory();
@Test @Test
public void testSetStaticParameters() throws Exception { void testSetStaticParameters() {
factory.setStaticParameters(Collections.singletonMap("foo", "bar")); this.factory.setStaticParameters(Collections.singletonMap("foo", "bar"));
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setBeanFactory(mock(BeanFactory.class));
factory.afterPropertiesSet(); this.factory.afterPropertiesSet();
SqlParameterSource source = factory.createParameterSource(null); SqlParameterSource source = this.factory.createParameterSource(null);
assertThat(source.hasValue("foo")).isTrue(); assertThat(source.hasValue("foo")).isTrue();
assertThat(source.getValue("foo")).isEqualTo("bar"); assertThat(source.getValue("foo")).isEqualTo("bar");
assertThat(source.getSqlType("foo")).isEqualTo(JdbcUtils.TYPE_UNKNOWN); assertThat(source.getSqlType("foo")).isEqualTo(JdbcUtils.TYPE_UNKNOWN);
} }
@Test @Test
public void testMapInput() throws Exception { void testMapInput() {
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setBeanFactory(mock(BeanFactory.class));
factory.afterPropertiesSet(); this.factory.afterPropertiesSet();
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar")); SqlParameterSource source = this.factory.createParameterSource(Collections.singletonMap("foo", "bar"));
assertThat(source.hasValue("foo")).isTrue(); assertThat(source.hasValue("foo")).isTrue();
assertThat(source.getValue("foo")).isEqualTo("bar"); assertThat(source.getValue("foo")).isEqualTo("bar");
assertThat(source.getSqlType("foo")).isEqualTo(JdbcUtils.TYPE_UNKNOWN); assertThat(source.getSqlType("foo")).isEqualTo(JdbcUtils.TYPE_UNKNOWN);
} }
@Test @Test
public void testListOfMapsInput() throws Exception { void testListOfMapsInput() {
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setBeanFactory(mock(BeanFactory.class));
factory.afterPropertiesSet(); this.factory.afterPropertiesSet();
SqlParameterSource source = factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"), SqlParameterSource source =
Collections.singletonMap("foo", "bucket"))); this.factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"),
Collections.singletonMap("foo", "bucket")));
String expression = "foo"; String expression = "foo";
assertThat(source.hasValue(expression)).isTrue(); assertThat(source.hasValue(expression)).isTrue();
assertThat(source.getValue(expression).toString()).isEqualTo("[bar, bucket]"); assertThat(source.getValue(expression).toString()).isEqualTo("[bar, bucket]");
@@ -72,10 +74,10 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
} }
@Test @Test
public void testMapInputWithExpression() throws Exception { void testMapInputWithExpression() {
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setBeanFactory(mock(BeanFactory.class));
factory.afterPropertiesSet(); this.factory.afterPropertiesSet();
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar")); SqlParameterSource source = this.factory.createParameterSource(Collections.singletonMap("foo", "bar"));
// This is an illegal parameter name in Spring JDBC so we'd never get this as input // This is an illegal parameter name in Spring JDBC so we'd never get this as input
assertThat(source.hasValue("foo.toUpperCase()")).isTrue(); assertThat(source.hasValue("foo.toUpperCase()")).isTrue();
assertThat(source.getValue("foo.toUpperCase()")).isEqualTo("BAR"); assertThat(source.getValue("foo.toUpperCase()")).isEqualTo("BAR");
@@ -83,35 +85,37 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
} }
@Test @Test
public void testMapInputWithMappedExpression() throws Exception { void testMapInputWithMappedExpression() {
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()")); this.factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setBeanFactory(mock(BeanFactory.class));
factory.afterPropertiesSet(); this.factory.afterPropertiesSet();
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar")); SqlParameterSource source = this.factory.createParameterSource(Collections.singletonMap("foo", "bar"));
assertThat(source.hasValue("spam")).isTrue(); assertThat(source.hasValue("spam")).isTrue();
assertThat(source.getValue("spam")).isEqualTo("BAR"); assertThat(source.getValue("spam")).isEqualTo("BAR");
assertThat(source.getSqlType("spam")).isEqualTo(JdbcUtils.TYPE_UNKNOWN); assertThat(source.getSqlType("spam")).isEqualTo(JdbcUtils.TYPE_UNKNOWN);
} }
@Test @Test
public void testMapInputWithMappedExpressionResolveStatic() throws Exception { void testMapInputWithMappedExpressionResolveStatic() {
factory.setParameterExpressions(Collections.singletonMap("spam", "#staticParameters['foo'].toUpperCase()")); this.factory.setParameterExpressions(
factory.setStaticParameters(Collections.singletonMap("foo", "bar")); Collections.singletonMap("spam", "#staticParameters['foo'].toUpperCase()"));
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setStaticParameters(Collections.singletonMap("foo", "bar"));
factory.afterPropertiesSet(); this.factory.setBeanFactory(mock(BeanFactory.class));
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("crap", "bucket")); this.factory.afterPropertiesSet();
SqlParameterSource source = this.factory.createParameterSource(Collections.singletonMap("crap", "bucket"));
assertThat(source.hasValue("spam")).isTrue(); assertThat(source.hasValue("spam")).isTrue();
assertThat(source.getValue("spam")).isEqualTo("BAR"); assertThat(source.getValue("spam")).isEqualTo("BAR");
assertThat(source.getSqlType("spam")).isEqualTo(JdbcUtils.TYPE_UNKNOWN); assertThat(source.getSqlType("spam")).isEqualTo(JdbcUtils.TYPE_UNKNOWN);
} }
@Test @Test
public void testListOfMapsInputWithExpression() throws Exception { void testListOfMapsInputWithExpression() {
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()")); this.factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setBeanFactory(mock(BeanFactory.class));
factory.afterPropertiesSet(); this.factory.afterPropertiesSet();
SqlParameterSource source = factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"), SqlParameterSource source =
Collections.singletonMap("foo", "bucket"))); this.factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"),
Collections.singletonMap("foo", "bucket")));
String expression = "spam"; String expression = "spam";
assertThat(source.hasValue(expression)).isTrue(); assertThat(source.hasValue(expression)).isTrue();
assertThat(source.getValue(expression).toString()).isEqualTo("[BAR, BUCKET]"); assertThat(source.getValue(expression).toString()).isEqualTo("[BAR, BUCKET]");
@@ -119,13 +123,14 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
} }
@Test @Test
public void testListOfMapsInputWithExpressionAndTypes() throws Exception { void testListOfMapsInputWithExpressionAndTypes() {
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()")); this.factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setBeanFactory(mock(BeanFactory.class));
factory.setSqlParameterTypes(Collections.singletonMap("spam", Types.SQLXML)); this.factory.setSqlParameterTypes(Collections.singletonMap("spam", Types.SQLXML));
factory.afterPropertiesSet(); this.factory.afterPropertiesSet();
SqlParameterSource source = factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"), SqlParameterSource source =
Collections.singletonMap("foo", "bucket"))); this.factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"),
Collections.singletonMap("foo", "bucket")));
String expression = "spam"; String expression = "spam";
assertThat(source.hasValue(expression)).isTrue(); assertThat(source.hasValue(expression)).isTrue();
assertThat(source.getValue(expression).toString()).isEqualTo("[BAR, BUCKET]"); assertThat(source.getValue(expression).toString()).isEqualTo("[BAR, BUCKET]");
@@ -133,17 +138,29 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
} }
@Test @Test
public void testListOfMapsInputWithExpressionAndEmptyTypes() throws Exception { void testListOfMapsInputWithExpressionAndEmptyTypes() {
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()")); this.factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
factory.setBeanFactory(mock(BeanFactory.class)); this.factory.setBeanFactory(mock(BeanFactory.class));
factory.setSqlParameterTypes(Collections.emptyMap()); this.factory.setSqlParameterTypes(Collections.emptyMap());
factory.afterPropertiesSet(); this.factory.afterPropertiesSet();
SqlParameterSource source = factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"), SqlParameterSource source =
Collections.singletonMap("foo", "bucket"))); this.factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"),
Collections.singletonMap("foo", "bucket")));
String expression = "spam"; String expression = "spam";
assertThat(source.hasValue(expression)).isTrue(); assertThat(source.hasValue(expression)).isTrue();
assertThat(source.getValue(expression).toString()).isEqualTo("[BAR, BUCKET]"); assertThat(source.getValue(expression).toString()).isEqualTo("[BAR, BUCKET]");
assertThat(source.getSqlType("spam")).isEqualTo(JdbcUtils.TYPE_UNKNOWN); assertThat(source.getSqlType("spam")).isEqualTo(JdbcUtils.TYPE_UNKNOWN);
} }
@Test
void testNullValue() {
this.factory.setStaticParameters(Collections.singletonMap("foo", null));
this.factory.setBeanFactory(mock(BeanFactory.class));
this.factory.afterPropertiesSet();
SqlParameterSource source = this.factory.createParameterSource(null);
assertThat(source.hasValue("foo")).isTrue();
assertThat(source.getValue("foo")).isNull();
assertThat(source.getSqlType("foo")).isEqualTo(JdbcUtils.TYPE_UNKNOWN);
}
} }