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:
Meherzad Lahewala
2017-11-04 19:32:44 +05:30
committed by Artem Bilan
parent d76af8c2aa
commit 854dba1366
5 changed files with 107 additions and 10 deletions

View File

@@ -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;

View File

@@ -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"));
}
}

View File

@@ -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" />

View File

@@ -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.

View File

@@ -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.