INT-3322 JDBC i-c-a SpEL Select ParameterSource
JIRA: https://jira.spring.io/browse/INT-3322 Support the use of an ExpressionEvaluatingSqlParameterSource from the ExpressionEvaluatingSqlParameterSourceFactory as the `select-sql-parameter-source` for an inbound channel adapter. Add documentation showing how to construct the bean. Add a mechanism to disable caching so that the expression is re-evaluated each time. However, the value should still be cached between the `hasValue()` and `getValue()` calls. INT-3322 Polishing; PR Comments
This commit is contained in:
committed by
Artem Bilan
parent
98b46c61f3
commit
c73cc40e23
@@ -125,7 +125,18 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
|
||||
@Override
|
||||
public SqlParameterSource createParameterSource(final Object input) {
|
||||
return new ExpressionEvaluatingSqlParameterSource(input, this.staticParameters, this.parameterExpressions);
|
||||
return new ExpressionEvaluatingSqlParameterSource(input, this.staticParameters, this.parameterExpressions, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an expression evaluating {@link SqlParameterSource} that does not cache it's results. Useful for cases
|
||||
* where the source is used multiple times, for example in a {@code <int-jdbc:inbound-channel-adapter/>} for the
|
||||
* {@code select-sql-parameter-source} attribute.
|
||||
* @param input The root object for the evaluation.
|
||||
* @return The parameter source.
|
||||
*/
|
||||
public SqlParameterSource createParameterSourceNoCache(final Object input) {
|
||||
return new ExpressionEvaluatingSqlParameterSource(input, this.staticParameters, this.parameterExpressions, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -138,21 +149,32 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
|
||||
private final Object input;
|
||||
|
||||
private volatile Map<String, Object> values = new HashMap<String, Object>();
|
||||
private final Map<String, Object> values = new HashMap<String, Object>();
|
||||
|
||||
private final Map<String, Expression[]> parameterExpressions;
|
||||
|
||||
private final boolean cache;
|
||||
|
||||
private ExpressionEvaluatingSqlParameterSource(Object input, Map<String, ?> staticParameters,
|
||||
Map<String, Expression[]> parameterExpressions) {
|
||||
Map<String, Expression[]> parameterExpressions, boolean cache) {
|
||||
this.input = input;
|
||||
this.parameterExpressions = parameterExpressions;
|
||||
this.values.putAll(staticParameters);
|
||||
this.cache = cache;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(String paramName) throws IllegalArgumentException {
|
||||
return this.doGetValue(paramName, false);
|
||||
}
|
||||
|
||||
public Object doGetValue(String paramName, boolean calledFromHasValue) throws IllegalArgumentException {
|
||||
if (values.containsKey(paramName)) {
|
||||
return values.get(paramName);
|
||||
Object cachedByHasValue = values.get(paramName);
|
||||
if (!this.cache) {
|
||||
values.remove(paramName);
|
||||
}
|
||||
return cachedByHasValue;
|
||||
}
|
||||
|
||||
if (!parameterExpressions.containsKey(paramName)) {
|
||||
@@ -174,7 +196,9 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
}
|
||||
|
||||
Object value = evaluateExpression(expression, input);
|
||||
values.put(paramName, value);
|
||||
if (this.cache || calledFromHasValue) {
|
||||
values.put(paramName, value);
|
||||
}
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Resolved expression " + expression + " to " + value);
|
||||
}
|
||||
@@ -184,7 +208,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
@Override
|
||||
public boolean hasValue(String paramName) {
|
||||
try {
|
||||
Object value = getValue(paramName);
|
||||
Object value = doGetValue(paramName, true);
|
||||
if (value == ERROR) {
|
||||
return false;
|
||||
}
|
||||
@@ -193,7 +217,9 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Could not evaluate expression", e);
|
||||
}
|
||||
values.put(paramName, ERROR);
|
||||
if (this.cache) {
|
||||
values.put(paramName, ERROR);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -202,6 +202,10 @@
|
||||
that query has
|
||||
placeholders (e.g. "SELECT * from FOO where KEY=:key") they
|
||||
will be bound from this source by name.
|
||||
Note: if you use the framework's 'ExpressionEvaluatingSqlParameterSourceFactory'
|
||||
to create a SpEL-based parameter source, be sure to use the 'createParameterSourceNoCache'
|
||||
method so that the expression will be re-evaluated on each poll. See the reference
|
||||
documentation for more information.
|
||||
</xsd:documentation>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.jdbc.core.namedparam.SqlParameterSource" />
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2014 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -129,6 +129,20 @@ public class JdbcPollingChannelAdapterParserTests {
|
||||
assertEquals("BAR", list.get(0).get("NAME"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectParameterSourceFactoryInboundChannelAdapter() {
|
||||
setUp("pollingWithSelectParameterSourceJdbcInboundChannelAdapterTest.xml", getClass());
|
||||
this.jdbcTemplate.update("insert into item values(1,'',42)");
|
||||
Message<?> message = messagingTemplate.receive();
|
||||
assertNotNull(message);
|
||||
assertEquals(42, ((Map<?,?>) ((List<?> )message.getPayload()).get(0)).get("STATUS"));
|
||||
this.jdbcTemplate.update("insert into item values(2,'',84)");
|
||||
this.appCtx.getBean(Status.class).which = 84;
|
||||
message = messagingTemplate.receive();
|
||||
assertNotNull(message);
|
||||
assertEquals(84, ((Map<?,?>) ((List<?> )message.getPayload()).get(0)).get("STATUS"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParameterSourceInboundChannelAdapter() {
|
||||
setUp("pollingWithParametersForMapJdbcInboundChannelAdapterTest.xml", getClass());
|
||||
@@ -141,6 +155,7 @@ public class JdbcPollingChannelAdapterParserTests {
|
||||
public void testMaxRowsInboundChannelAdapter() {
|
||||
setUp("pollingWithMaxRowsJdbcInboundChannelAdapterTest.xml", getClass());
|
||||
new TransactionTemplate(transactionManager).execute(new TransactionCallback<Void>() {
|
||||
@Override
|
||||
public Void doInTransaction(TransactionStatus status) {
|
||||
jdbcTemplate.update("insert into item values(1,'',2)");
|
||||
jdbcTemplate.update("insert into item values(2,'',2)");
|
||||
@@ -200,14 +215,26 @@ public class JdbcPollingChannelAdapterParserTests {
|
||||
|
||||
public static class TestSqlParameterSource extends AbstractSqlParameterSource {
|
||||
|
||||
@Override
|
||||
public Object getValue(String paramName) throws IllegalArgumentException {
|
||||
return 2;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasValue(String paramName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class Status {
|
||||
|
||||
private int which = 42;
|
||||
|
||||
public int which() {
|
||||
return this.which;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans:beans xmlns="http://www.springframework.org/schema/integration/jdbc"
|
||||
xmlns:beans="http://www.springframework.org/schema/beans"
|
||||
xmlns:si="http://www.springframework.org/schema/integration"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans
|
||||
http://www.springframework.org/schema/beans/spring-beans.xsd
|
||||
http://www.springframework.org/schema/integration
|
||||
http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/integration/jdbc
|
||||
http://www.springframework.org/schema/integration/jdbc/spring-integration-jdbc.xsd">
|
||||
|
||||
<inbound-channel-adapter query="select * from item where status=:status" channel="target"
|
||||
data-source="dataSource" select-sql-parameter-source="parameterSource"
|
||||
update="delete from item" />
|
||||
|
||||
<beans:import resource="jdbcInboundChannelAdapterCommonConfig.xml" />
|
||||
|
||||
<beans:bean id="parameterSource" factory-bean="parameterSourceFactory" factory-method="createParameterSourceNoCache">
|
||||
<beans:constructor-arg value="" />
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="parameterSourceFactory" class="org.springframework.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
|
||||
<beans:property name="parameterExpressions">
|
||||
<beans:map>
|
||||
<beans:entry key="status" value="@statusBean.which()" />
|
||||
</beans:map>
|
||||
</beans:property>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="statusBean" class="org.springframework.integration.jdbc.config.JdbcPollingChannelAdapterParserTests$Status" />
|
||||
|
||||
</beans:beans>
|
||||
Reference in New Issue
Block a user