INT-1783: add parameterExpressions to expression evaluating sql parameter source

This commit is contained in:
Dave Syer
2011-02-04 15:06:32 +00:00
parent 031aa372c0
commit 1b44da28c2
4 changed files with 91 additions and 7 deletions

View File

@@ -42,22 +42,65 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
private Map<String, ?> staticParameters;
private Map<String, String> parameterExpressions;
public ExpressionEvaluatingSqlParameterSourceFactory() {
this.staticParameters = Collections.unmodifiableMap(new HashMap<String, Object>());
this.parameterExpressions = Collections.unmodifiableMap(new HashMap<String, String>());
}
/**
* If the input is a List or a Map, the output is a map parameter source, and in that case some static parameters
* can be added (default is empty). If the input is not a List or a Map then this value is ignored.
* Define some static parameter values. These take precedence over those defined as expressions in the
* {@link #setParameterExpressions(Map) parameterExpressions}, so a parameter in the query will be filled from here
* first, and then from the expressions.
*
* @param staticParameters the static parameters to set
*/
public void setStaticParameters(Map<String, ?> staticParameters) {
this.staticParameters = staticParameters;
getEvaluationContext().setVariable("staticParameters", staticParameters);
}
/**
* Optionally maps parameter names to explicit expressions. The named parameter support in Spring is limited to
* simple parameter names with no special characters, so this feature allows you to specify a simple name in the SQL
* query and then have it translated into an expression at runtime. The target of the expression depends on the
* context: generally in an outbound setting it is a Message, and in an inbound setting it is a result set row (a
* Map or a domain object if a RowMapper has been provided). The {@link #setStaticParameters(Map) static parameters}
* can be referred to in an expression using the variable <code>#staticParameters</code>, for example:
*
* <table border="1" cellspacing="1" cellpadding="1">
* <tr>
* <th><b>Key</b></th>
* <th><b>Value (Expression)</b></th>
* <th><b>Example SQL</b></th>
* </tr>
* <tr>
* <td>id</td>
* <td>payload.businessKey</td>
* <td>select * from items where id=:id</td>
* </tr>
* <tr>
* <td>date</td>
* <td>headers['timestamp']</td>
* <td>select * from items where created>:date</td>
* </tr>
* <tr>
* <td>key</td>
* <td>#staticParameters['foo'].toUpperCase()</td>
* <td>select * from items where name=:key</td>
* </tr>
* </pre>
*
* @param parameterExpressions the parameter expressions to set
*/
public void setParameterExpressions(Map<String, String> parameterExpressions) {
this.parameterExpressions = parameterExpressions;
}
public SqlParameterSource createParameterSource(final Object input) {
SqlParameterSource toReturn = new ExpressionEvaluatingSqlParameterSource(input, staticParameters);
SqlParameterSource toReturn = new ExpressionEvaluatingSqlParameterSource(input, staticParameters,
parameterExpressions);
return toReturn;
}
@@ -67,8 +110,12 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
private Map<String, Object> values = new ConcurrentHashMap<String, Object>();
private ExpressionEvaluatingSqlParameterSource(Object input, Map<String, ?> staticParameters) {
private final Map<String, String> parameterExpressions;
private ExpressionEvaluatingSqlParameterSource(Object input, Map<String, ?> staticParameters,
Map<String, String> parameterExpressions) {
this.input = input;
this.parameterExpressions = parameterExpressions;
this.values.putAll(staticParameters);
}
@@ -77,8 +124,11 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
return values.get(paramName);
}
String expression = paramName;
if (parameterExpressions.containsKey(expression)) {
expression = parameterExpressions.get(expression);
}
if (input instanceof Collection<?>) {
expression = "#root.![" + paramName + "]";
expression = "#root.![" + expression + "]";
}
Object value = evaluateExpression(expression, input);
values.put(paramName, value);

View File

@@ -60,8 +60,37 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
@Test
public void testMapInputWithExpression() {
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar"));
// This is an illegal parameter name in Spring JDBC so we'd never get this as input
assertTrue(source.hasValue("foo.toUpperCase()"));
assertEquals("BAR", source.getValue("foo.toUpperCase()"));
}
@Test
public void testMapInputWithMappedExpression() {
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar"));
assertTrue(source.hasValue("spam"));
assertEquals("BAR", source.getValue("spam"));
}
@Test
public void testMapInputWithMappedExpressionResolveStatic() {
factory.setParameterExpressions(Collections.singletonMap("spam", "#staticParameters['foo'].toUpperCase()"));
factory.setStaticParameters(Collections.singletonMap("foo", "bar"));
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("crap", "bucket"));
assertTrue(source.hasValue("spam"));
assertEquals("BAR", source.getValue("spam"));
}
@Test
public void testListOfMapsInputWithExpression() {
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
@SuppressWarnings("unchecked")
SqlParameterSource source = factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"),
Collections.singletonMap("foo", "bucket")));
String expression = "spam";
assertTrue(source.hasValue(expression));
assertEquals("[BAR, BUCKET]", source.getValue(expression).toString());
}
}

View File

@@ -116,7 +116,7 @@ public class JdbcPollingChannelAdapterParserTests {
assertNotNull(message);
List<Map<String, Object>> list = jdbcTemplate.queryForList("SELECT * FROM item WHERE status=1");
assertEquals(1, list.size());
assertEquals("bar", list.get(0).get("NAME"));
assertEquals("BAR", list.get(0).get("NAME"));
}
@Test

View File

@@ -10,12 +10,17 @@
http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd">
<inbound-channel-adapter query="select * from item where status=2" channel="target"
update="update item set status=1, name=:foo where id in (:id)" jdbc-operations="jdbcTemplate"
update="update item set status=1, name=:name where id in (:id)" jdbc-operations="jdbcTemplate"
update-sql-parameter-source-factory="sqlParameterSourceFactory" />
<beans:import resource="jdbcInboundChannelAdapterCommonConfig.xml" />
<beans:bean id="sqlParameterSourceFactory" class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
<beans:property name="parameterExpressions">
<beans:map>
<beans:entry key="name" value="'bar'.toUpperCase()" />
</beans:map>
</beans:property>
<beans:property name="staticParameters">
<beans:map>
<beans:entry key="foo" value="bar" />