INT-4291 Add ExprEvalSqlPSF.setSqlParameterTypes
JIRA: https://jira.spring.io/browse/INT-4291 * Fix checkstyle trailing space *Use correct way to constants in spring xml and fix test case * Polishing - Update javadoc and rename method name to relate more to the behavior
This commit is contained in:
committed by
Artem Bilan
parent
d76af8c2aa
commit
854dba1366
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -40,6 +40,7 @@ import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
* @author Oleg Zhurakousky
|
||||
* @author Gary Russell
|
||||
* @author Artem Bilan
|
||||
* @author Meherzad Lahewala
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpressionEvaluator implements
|
||||
@@ -53,6 +54,8 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
|
||||
private volatile Map<String, ?> staticParameters;
|
||||
|
||||
private volatile Map<String, Integer> sqlParametersTypes;
|
||||
|
||||
/**
|
||||
* The {@link Map} of parameters with expressions.
|
||||
* {@code key} - parameter name; {@code value} - array of two {@link Expression}s:
|
||||
@@ -126,9 +129,23 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
this.parameterExpressions = paramExpressions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Optionally set parameter sql types for the used parameters. Use
|
||||
* {@link java.sql.Types} to get the parameter type value.
|
||||
* @param sqlParametersTypes the parameter type to use
|
||||
* @since 5.0
|
||||
* @see java.sql.Types
|
||||
*/
|
||||
public void setSqlParameterTypes(Map<String, Integer> sqlParametersTypes) {
|
||||
this.sqlParametersTypes = sqlParametersTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqlParameterSource createParameterSource(final Object input) {
|
||||
return new ExpressionEvaluatingSqlParameterSource(input, this.staticParameters, this.parameterExpressions, true);
|
||||
AbstractSqlParameterSource sqlParameterSource = new ExpressionEvaluatingSqlParameterSource(input,
|
||||
this.staticParameters, this.parameterExpressions, true);
|
||||
registerSqlTypes(sqlParameterSource);
|
||||
return sqlParameterSource;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -139,7 +156,10 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
* @return The parameter source.
|
||||
*/
|
||||
public SqlParameterSource createParameterSourceNoCache(final Object input) {
|
||||
return new ExpressionEvaluatingSqlParameterSource(input, this.staticParameters, this.parameterExpressions, false);
|
||||
AbstractSqlParameterSource sqlParameterSource = new ExpressionEvaluatingSqlParameterSource(input,
|
||||
this.staticParameters, this.parameterExpressions, false);
|
||||
registerSqlTypes(sqlParameterSource);
|
||||
return sqlParameterSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -148,6 +168,12 @@ public class ExpressionEvaluatingSqlParameterSourceFactory extends AbstractExpre
|
||||
this.getEvaluationContext().setVariable("staticParameters", this.staticParameters);
|
||||
}
|
||||
|
||||
private void registerSqlTypes(AbstractSqlParameterSource sqlParameterSource) {
|
||||
if (this.sqlParametersTypes != null) {
|
||||
this.sqlParametersTypes.forEach(sqlParameterSource::registerSqlType);
|
||||
}
|
||||
}
|
||||
|
||||
private final class ExpressionEvaluatingSqlParameterSource extends AbstractSqlParameterSource {
|
||||
|
||||
private final Object input;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
* Copyright 2002-2017 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.
|
||||
@@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import java.sql.Types;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -27,10 +28,11 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.factory.BeanFactory;
|
||||
import org.springframework.jdbc.core.namedparam.SqlParameterSource;
|
||||
import org.springframework.jdbc.support.JdbcUtils;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @author Meherzad Lahewala
|
||||
*/
|
||||
public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
|
||||
|
||||
@@ -44,6 +46,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
|
||||
SqlParameterSource source = factory.createParameterSource(null);
|
||||
assertTrue(source.hasValue("foo"));
|
||||
assertEquals("bar", source.getValue("foo"));
|
||||
assertEquals(JdbcUtils.TYPE_UNKNOWN, source.getSqlType("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -53,18 +56,19 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
|
||||
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar"));
|
||||
assertTrue(source.hasValue("foo"));
|
||||
assertEquals("bar", source.getValue("foo"));
|
||||
assertEquals(JdbcUtils.TYPE_UNKNOWN, source.getSqlType("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListOfMapsInput() throws Exception {
|
||||
factory.setBeanFactory(mock(BeanFactory.class));
|
||||
factory.afterPropertiesSet();
|
||||
@SuppressWarnings("unchecked")
|
||||
SqlParameterSource source = factory.createParameterSource(Arrays.asList(Collections.singletonMap("foo", "bar"),
|
||||
Collections.singletonMap("foo", "bucket")));
|
||||
String expression = "foo";
|
||||
assertTrue(source.hasValue(expression));
|
||||
assertEquals("[bar, bucket]", source.getValue(expression).toString());
|
||||
assertEquals(JdbcUtils.TYPE_UNKNOWN, source.getSqlType(expression));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -75,6 +79,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
|
||||
// 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()"));
|
||||
assertEquals(JdbcUtils.TYPE_UNKNOWN, source.getSqlType("food"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -85,6 +90,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
|
||||
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("foo", "bar"));
|
||||
assertTrue(source.hasValue("spam"));
|
||||
assertEquals("BAR", source.getValue("spam"));
|
||||
assertEquals(JdbcUtils.TYPE_UNKNOWN, source.getSqlType("spam"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -96,6 +102,7 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
|
||||
SqlParameterSource source = factory.createParameterSource(Collections.singletonMap("crap", "bucket"));
|
||||
assertTrue(source.hasValue("spam"));
|
||||
assertEquals("BAR", source.getValue("spam"));
|
||||
assertEquals(JdbcUtils.TYPE_UNKNOWN, source.getSqlType("spam"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -103,12 +110,39 @@ public class ExpressionEvaluatingSqlParameterSourceFactoryTests {
|
||||
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
|
||||
factory.setBeanFactory(mock(BeanFactory.class));
|
||||
factory.afterPropertiesSet();
|
||||
@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());
|
||||
assertEquals(JdbcUtils.TYPE_UNKNOWN, source.getSqlType("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListOfMapsInputWithExpressionAndTypes() throws Exception {
|
||||
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
|
||||
factory.setBeanFactory(mock(BeanFactory.class));
|
||||
factory.setSqlParameterTypes(Collections.singletonMap("spam", Types.SQLXML));
|
||||
factory.afterPropertiesSet();
|
||||
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());
|
||||
assertEquals(Types.SQLXML, source.getSqlType("spam"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testListOfMapsInputWithExpressionAndEmptyTypes() throws Exception {
|
||||
factory.setParameterExpressions(Collections.singletonMap("spam", "foo.toUpperCase()"));
|
||||
factory.setBeanFactory(mock(BeanFactory.class));
|
||||
factory.setSqlParameterTypes(Collections.emptyMap());
|
||||
factory.afterPropertiesSet();
|
||||
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());
|
||||
assertEquals(JdbcUtils.TYPE_UNKNOWN, source.getSqlType("spam"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,17 +15,22 @@
|
||||
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:property name="sqlParameterTypes">
|
||||
<beans:map>
|
||||
<beans:entry key="status" value="#{ T(java.sql.Types).INTEGER}" />
|
||||
</beans:map>
|
||||
</beans:property>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="statusBean" class="org.springframework.integration.jdbc.config.JdbcPollingChannelAdapterParserTests$Status" />
|
||||
|
||||
@@ -81,6 +81,33 @@ The `value` in each parameter expression can be any valid SpEL expression.
|
||||
The `#root` object for the expression evaluation is the constructor argument defined on the `parameterSource` bean.
|
||||
It is static for all evaluations (in this case, an empty String).
|
||||
|
||||
Starting with _version 5.0_, you can use pass parameter types using `setSqlParameterTypes` method in
|
||||
the `ExpressionEvaluatingSqlParameterSourceFactory` can be supplied with the sqlParameterTypes to specify the target SQL type for the particular parameter.
|
||||
|
||||
Below example provides sql type for the parameters being used in the query.
|
||||
|
||||
[source,xml]
|
||||
----
|
||||
<int-jdbc:inbound-channel-adapter query="select * from item where status=:status"
|
||||
channel="target" data-source="dataSource"
|
||||
select-sql-parameter-source="parameterSource" />
|
||||
|
||||
<bean id="parameterSource" factory-bean="parameterSourceFactory"
|
||||
factory-method="createParameterSourceNoCache">
|
||||
<constructor-arg value="" />
|
||||
</bean>
|
||||
|
||||
<bean id="parameterSourceFactory"
|
||||
class="o.s.integration.jdbc.ExpressionEvaluatingSqlParameterSourceFactory">
|
||||
<property name="sqlParameterTypes">
|
||||
<map>
|
||||
<entry key="status" value=""#{ T(java.sql.Types).BINARY}" />
|
||||
</map>
|
||||
</property>
|
||||
</bean>
|
||||
|
||||
----
|
||||
|
||||
IMPORTANT: Use the `createParameterSourceNoCache` factory method; otherwise the parameter source will cache the result of the evaluation.
|
||||
Also note that, because caching is disabled, if the same parameter name appears in the select query multiple times, it will be re-evaluated for each occurrence.
|
||||
|
||||
|
||||
@@ -292,8 +292,13 @@ The `GemfireMetadataStore` now implements `ListenableMetadataStore`, allowing us
|
||||
|
||||
See <<gemfire>> for more information.
|
||||
|
||||
==== Jdbc Message Channel Store Changes
|
||||
==== Jdbc Changes
|
||||
|
||||
The `JdbcMessageChannelStore` now provides setter for the `ChannelMessageStorePreparedStatementSetter` allowing users to customize a message insertion in the store.
|
||||
|
||||
See <<jdbc-message-store-channels>> for more information.
|
||||
|
||||
The `ExpressionEvaluatingSqlParameterSourceFactory` now provides setter for the sqlParameterTypes allowing users
|
||||
to customize sql types of the parameters.
|
||||
|
||||
See <<jdbc-inbound-channel-adapter>> for more information.
|
||||
Reference in New Issue
Block a user