From 1b44da28c21d0e2a9d73d5937cf97c3d6780d9b4 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Fri, 4 Feb 2011 15:06:32 +0000 Subject: [PATCH] INT-1783: add parameterExpressions to expression evaluating sql parameter source --- ...onEvaluatingSqlParameterSourceFactory.java | 60 +++++++++++++++++-- ...luatingSqlParameterSourceFactoryTests.java | 29 +++++++++ .../JdbcPollingChannelAdapterParserTests.java | 2 +- ...terSourceJdbcInboundChannelAdapterTest.xml | 7 ++- 4 files changed, 91 insertions(+), 7 deletions(-) diff --git a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java index 8a76174132..62ed668b69 100644 --- a/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java +++ b/spring-integration-jdbc/src/main/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactory.java @@ -42,22 +42,65 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre private Map staticParameters; + private Map parameterExpressions; + public ExpressionEvaluatingSqlParameterSourceFactory() { this.staticParameters = Collections.unmodifiableMap(new HashMap()); + this.parameterExpressions = Collections.unmodifiableMap(new HashMap()); } /** - * 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 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 #staticParameters, for example: + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * @param parameterExpressions the parameter expressions to set + */ + public void setParameterExpressions(Map 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 values = new ConcurrentHashMap(); - private ExpressionEvaluatingSqlParameterSource(Object input, Map staticParameters) { + private final Map parameterExpressions; + + private ExpressionEvaluatingSqlParameterSource(Object input, Map staticParameters, + Map 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); diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactoryTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactoryTests.java index ef55c09b7f..3da48a671a 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactoryTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/ExpressionEvaluatingSqlParameterSourceFactoryTests.java @@ -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()); + } + } diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParserTests.java b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParserTests.java index c6a51dcc06..6a33bc16e5 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParserTests.java +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/JdbcPollingChannelAdapterParserTests.java @@ -116,7 +116,7 @@ public class JdbcPollingChannelAdapterParserTests { assertNotNull(message); List> 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 diff --git a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/pollingWithParameterSourceJdbcInboundChannelAdapterTest.xml b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/pollingWithParameterSourceJdbcInboundChannelAdapterTest.xml index 2a6afc85b3..d268619c89 100644 --- a/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/pollingWithParameterSourceJdbcInboundChannelAdapterTest.xml +++ b/spring-integration-jdbc/src/test/java/org/springframework/integration/jdbc/config/pollingWithParameterSourceJdbcInboundChannelAdapterTest.xml @@ -10,12 +10,17 @@ http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd"> + + + + +
KeyValue (Expression)Example SQL
idpayload.businessKeyselect * from items where id=:id
dateheaders['timestamp']select * from items where created>:date
key#staticParameters['foo'].toUpperCase()select * from items where name=:key