INT-4559: JDBC Gateway: return List for maxRows>1

JIRA: https://jira.spring.io/browse/INT-4559

* Return a single item from result only if
`maxRows == null || maxRows == 1`
* Remove deprecated `max-rows-per-poll` from the
`JdbcOutboundGateway.java` and its XSD and parsers
This commit is contained in:
Artem Bilan
2019-02-22 15:59:15 -05:00
committed by Gary Russell
parent 1d54f9663a
commit aa075439fc
6 changed files with 33 additions and 87 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -21,6 +21,7 @@ import java.util.List;
import javax.sql.DataSource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.integration.handler.AbstractReplyProducingMessageHandler;
import org.springframework.jdbc.core.JdbcOperations;
@@ -89,24 +90,12 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
}
/**
* The maximum number of rows to pull out of the query results per poll (if
* greater than zero, otherwise all rows will be packed into the outgoing message).
* The value is ultimately set on the underlying {@link JdbcPollingChannelAdapter}.
* If not specified this value will default to {@code 1}.
* This parameter is only applicable if a selectQuery was provided. Null values
* are not permitted.
* @param maxRowsPerPoll the number of rows to select. Must not be null.
* @deprecated since 5.1 in favor of {@link #setMaxRows(Integer)}
*/
@Deprecated
public void setMaxRowsPerPoll(Integer maxRowsPerPoll) {
setMaxRows(maxRowsPerPoll);
}
/**
* The maximum number of rows to query.
* The value is ultimately set on the underlying {@link JdbcPollingChannelAdapter}.
* The value is set on the underlying {@link JdbcPollingChannelAdapter}.
* Also used to check before producing reply:
* if result has only one item and {@code maxRows} is not set or configured to {@code 1},
* only that item is returned. Otherwise the whole list.
* If not specified this value will default to {@code 1}.
* This parameter is only applicable if a selectQuery was provided. Null values
* are not permitted.
@@ -159,32 +148,29 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
this.poller.setMaxRows(this.maxRows);
}
BeanFactory beanFactory = getBeanFactory();
if (this.handler != null) {
this.handler.setBeanFactory(this.getBeanFactory());
this.handler.setBeanFactory(beanFactory);
this.handler.afterPropertiesSet();
}
if (!this.sqlParameterSourceFactorySet && this.getBeanFactory() != null) {
if (!this.sqlParameterSourceFactorySet && beanFactory != null) {
((ExpressionEvaluatingSqlParameterSourceFactory) this.sqlParameterSourceFactory)
.setBeanFactory(this.getBeanFactory());
.setBeanFactory(beanFactory);
}
}
@Override
protected Object handleRequestMessage(Message<?> requestMessage) {
List<?> list;
List<?> list = Collections.emptyList();
if (this.handler != null) {
list = this.handler.executeUpdateQuery(requestMessage, this.keysGenerated);
}
else {
list = Collections.emptyList();
}
if (this.poller != null) {
SqlParameterSource sqlQueryParameterSource = this.sqlParameterSourceFactory
.createParameterSource(requestMessage);
SqlParameterSource sqlQueryParameterSource =
this.sqlParameterSourceFactory.createParameterSource(requestMessage);
if (this.keysGenerated) {
if (!list.isEmpty()) {
if (list.size() == 1) {
@@ -196,15 +182,12 @@ public class JdbcOutboundGateway extends AbstractReplyProducingMessageHandler im
}
}
list = this.poller.doPoll(sqlQueryParameterSource);
if (list.isEmpty()) {
return null;
}
}
Object payload = list;
if (list.isEmpty()) {
return null;
}
if (list.size() == 1) {
if (list.size() == 1 && (this.maxRows == null || this.maxRows == 1)) {
payload = list.get(0);
}
return payload;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -71,24 +71,6 @@ public class JdbcOutboundGatewayParser extends AbstractConsumerEndpointParser {
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element,
"request-prepared-statement-setter");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "row-mapper");
// TODO remove deprecated option in the next version
boolean hasMaxRowsPerPoll = element.hasAttribute("max-rows-per-poll");
boolean hasMaxRows = element.hasAttribute("max-rows");
if (hasMaxRowsPerPoll) {
parserContext.getReaderContext()
.warning("The 'max-rows-per-poll' is deprecated in favor of 'max-rows'", element);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll");
if (hasMaxRows) {
parserContext.getReaderContext()
.warning("The 'max-rows' has a precedence over 'max-rows-per-poll'", element);
}
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "keys-generated");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "reply-timeout", "sendTimeout");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2018 the original author or authors.
* Copyright 2002-2019 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.
@@ -74,25 +74,7 @@ public class JdbcPollingChannelAdapterParser extends AbstractPollingInboundChann
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "row-mapper");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "update-sql-parameter-source-factory");
IntegrationNamespaceUtils.setReferenceIfAttributeDefined(builder, element, "select-sql-parameter-source");
// TODO remove deprecated option in the next version
boolean hasMaxRowsPerPoll = element.hasAttribute("max-rows-per-poll");
boolean hasMaxRows = element.hasAttribute("max-rows");
if (hasMaxRowsPerPoll) {
parserContext.getReaderContext()
.warning("The 'max-rows-per-poll' is deprecated in favor of 'max-rows'", element);
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows-per-poll");
if (hasMaxRows) {
parserContext.getReaderContext()
.warning("The 'max-rows' has a precedence over 'max-rows-per-poll'", element);
}
}
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "max-rows");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "update", "updateSql");
IntegrationNamespaceUtils.setValueIfAttributeDefined(builder, element, "update-per-row");

View File

@@ -367,18 +367,6 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="max-rows-per-poll" type="xsd:string">
<xsd:annotation>
<xsd:documentation>
[DEPRECATED] When using a select query, you can set a
custom limit regarding the number of rows
extracted. Otherwise by default only the first
row will be extracted into the outgoing message.
If set to '0' all rows are extracted.
Deprecated since 5.1 in favor of 'max-rows'.
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="max-rows" type="xsd:string">
<xsd:annotation>
<xsd:documentation>

View File

@@ -24,6 +24,7 @@ import static org.mockito.Mockito.verify;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
@@ -222,7 +223,7 @@ public class JdbcOutboundGatewayParserTests {
accessor = new DirectFieldAccessor(messagingTemplate);
Long sendTimeout = (Long) accessor.getPropertyValue("sendTimeout");
Long sendTimeout = (Long) accessor.getPropertyValue("sendTimeout");
assertThat(sendTimeout).as("Wrong sendTimeout").isEqualTo(Long.valueOf(444L));
}
@@ -258,7 +259,8 @@ public class JdbcOutboundGatewayParserTests {
assertThat(maxRowsPerPoll).as("maxRowsPerPoll should default to 10").isEqualTo(Integer.valueOf(10));
}
@Test //INT-1029
@Test
@SuppressWarnings("unchecked")
public void testOutboundGatewayInsideChain() {
setUp("handlingMapPayloadJdbcOutboundGatewayTest.xml", getClass());
@@ -274,10 +276,18 @@ public class JdbcOutboundGatewayParserTests {
PollableChannel outbound = this.context.getBean("replyChannel", PollableChannel.class);
Message<?> reply = outbound.receive(10000);
assertThat(reply).isNotNull();
@SuppressWarnings("unchecked")
Map<String, ?> payload = (Map<String, ?>) reply.getPayload();
assertThat(payload.get("name")).isEqualTo("bar");
assertThat(reply)
.isNotNull()
.extracting(Message::getPayload)
.isInstanceOf(List.class)
.asList()
.hasSize(1)
.element(0)
.isInstanceOf(Map.class)
.satisfies(map -> assertThat((Map<String, String>) map)
.containsEntry("name", "bar"));
}

View File

@@ -26,6 +26,7 @@
<si:chain input-channel="jdbcOutboundGatewayInsideChain" output-channel="replyChannel">
<outbound-gateway id="jdbc-outbound-gateway-within-chain" query="select * from foos where id=:headers[id]"
update="insert into foos (id, status, name) values (:headers[id], 0, :payload[foo])"
max-rows="2"
data-source="dataSource" requires-reply="false"/>
</si:chain>