diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java
index 16343ac985..b0f866b5e5 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/AbstractConsumerEndpointParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -95,12 +95,19 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
String inputChannelAttributeName = this.getInputChannelAttributeName();
boolean hasInputChannelAttribute = element.hasAttribute(inputChannelAttributeName);
if (parserContext.isNested()) {
+ String elementDescription = IntegrationNamespaceUtils.createElementDescription(element);
if (hasInputChannelAttribute) {
- String elementDescription = IntegrationNamespaceUtils.createElementDescription(element);
parserContext.getReaderContext().error("The '" + inputChannelAttributeName
+ "' attribute isn't allowed for a nested (e.g. inside a ) endpoint element: "
+ elementDescription + ".", element);
}
+ if (!replyChannelInChainAllowed(element)) {
+ if (StringUtils.hasText(element.getAttribute("reply-channel"))) {
+ parserContext.getReaderContext().error("The 'reply-channel' attribute isn't"
+ + " allowed for a nested (e.g. inside a ) outbound gateway element: "
+ + elementDescription + ".", element);
+ }
+ }
return handlerBeanDefinition;
}
else {
@@ -168,4 +175,14 @@ public abstract class AbstractConsumerEndpointParser extends AbstractBeanDefinit
return null;
}
+ /**
+ * Override to allow 'reply-channel' within a chain, for components where it
+ * makes sense (e.g. enricher). Default is false for outbound gateways, else true.
+ * @return true to allow a reply channel attribute within a chain.
+ */
+ protected boolean replyChannelInChainAllowed(Element element) {
+ String localName = element.getLocalName();
+ return localName == null || !localName.contains("outbound-gateway");
+ }
+
}
diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/EnricherParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/EnricherParser.java
index 0f97644fdb..94543dec93 100644
--- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/EnricherParser.java
+++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/EnricherParser.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 the original author or authors.
+ * Copyright 2002-2015 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.
@@ -42,6 +42,7 @@ import org.springframework.util.xml.DomUtils;
* @author Artem Bilan
* @author Liujiong
* @author Kris Jacyna
+ * @author Gary Russell
* @since 2.1
*/
public class EnricherParser extends AbstractConsumerEndpointParser {
@@ -201,4 +202,9 @@ public class EnricherParser extends AbstractConsumerEndpointParser {
return builder;
}
+ @Override
+ protected boolean replyChannelInChainAllowed(Element element) {
+ return true;
+ }
+
}
diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/EnricherParserTests5-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/EnricherParserTests5-context.xml
index a6f75c7df6..72bf561dbb 100644
--- a/spring-integration-core/src/test/java/org/springframework/integration/config/xml/EnricherParserTests5-context.xml
+++ b/spring-integration-core/src/test/java/org/springframework/integration/config/xml/EnricherParserTests5-context.xml
@@ -11,16 +11,20 @@
+
+
-
-
-
-
+
+
+
+
+
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java
index ac37df71e7..bf36afd0f9 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/JmsOutboundGatewayParserTests.java
@@ -16,10 +16,13 @@
package org.springframework.integration.jms.config;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
@@ -249,6 +252,12 @@ public class JmsOutboundGatewayParserTests {
String result = gateway.echo("hello");
verify(handler, times(1)).handleMessage(Mockito.any(Message.class));
assertEquals("hello", result);
+ JmsOutboundGateway gw1 = context.getBean("chain1$child.gateway.handler", JmsOutboundGateway.class);
+ MessageChannel out = TestUtils.getPropertyValue(gw1, "outputChannel", MessageChannel.class);
+ assertThat(out.getClass().getSimpleName(), equalTo("ReplyForwardingMessageChannel"));
+ JmsOutboundGateway gw2 = context.getBean("chain2$child.gateway.handler", JmsOutboundGateway.class);
+ out = TestUtils.getPropertyValue(gw2, "outputChannel", MessageChannel.class);
+ assertThat(out.getClass().getName(), containsString("MessageHandlerChain$"));
context.close();
}
diff --git a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/gatewayMaintainsReplyChannel.xml b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/gatewayMaintainsReplyChannel.xml
index 3e5cae5a01..9f0af69626 100644
--- a/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/gatewayMaintainsReplyChannel.xml
+++ b/spring-integration-jms/src/test/java/org/springframework/integration/jms/config/gatewayMaintainsReplyChannel.xml
@@ -6,7 +6,7 @@
http://www.springframework.org/schema/integration/jms http://www.springframework.org/schema/integration/jms/spring-integration-jms.xsd"
xmlns:int="http://www.springframework.org/schema/integration"
xmlns:int-jms="http://www.springframework.org/schema/integration/jms">
-
+
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
@@ -37,7 +67,7 @@
-
+
@@ -48,11 +78,11 @@
-
+
-
+
-
+
diff --git a/src/reference/asciidoc/whats-new.adoc b/src/reference/asciidoc/whats-new.adoc
index 95b3329a9c..29f9625004 100644
--- a/src/reference/asciidoc/whats-new.adoc
+++ b/src/reference/asciidoc/whats-new.adoc
@@ -13,3 +13,10 @@ development process.
[[x4.3-general]]
=== General Changes
+==== Outbound Gateway within Chain
+
+Previously, it was possible to specify a `reply-channel` on an outbound gateway within a chain.
+It was completely ignored; the gateway's reply goes to the next chain element, or to the chain's output channel
+if the gateway is the last element.
+This condition is now detected and disallowed.
+If you have such configuration, simply remove the `reply-channel`.