spring integration: service activator requires-reply="false" usage

Aravind Yarram picture Aravind Yarram · Jan 25, 2013 · Viewed 15.5k times · Source

Why am I receiving the below exception even after I've specified requires-reply="false"

Exception

org.springframework.integration.support.channel.ChannelResolutionException: no output-channel or replyChannel header available

Config

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:int="http://www.springframework.org/schema/integration"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
        http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration-2.1.xsd">

    <int:channel id="inChannel">

    </int:channel>

    <bean id="upperService" class="sipackage.service.UppercaseService"></bean>

    <int:service-activator requires-reply="false" input-channel="inChannel" ref="upperService" method="toUpper"></int:service-activator>
</beans>

JUnit

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/META-INF/spring/integration/sample.xml"})
public class ChannelTest {

    @Autowired MessageChannel inChannel;

    @Test
    public void test() {

        boolean sendOutcome=inChannel.send(MessageBuilder.withPayload("Hello, there 1!").build());
        assertTrue(sendOutcome);

        sendOutcome=inChannel.send(MessageBuilder.withPayload("Hello, there 2!").build());
        assertTrue(sendOutcome);
    }

}

Service

public class UppercaseService {

public String toUpper(String msg)
{
    return msg.toUpperCase();
}
}

Answer

Ryan Stewart picture Ryan Stewart · Jan 25, 2013

As per "Configuring Service Activator":

when the service method returns a non-null value, the endpoint will attempt to send the reply message to an appropriate reply channel. To determine the reply channel, it will first check if an "output-channel" was provided in the endpoint configuration... If no "output-channel" is available, it will then check the Message's replyChannel header value.

What it doesn't mention there is that the basic behavior of any reply-producing message handler is that if it doesn't find anything with those two checks, it throws an exception, as can be seen in the sendReplyMessage() method of the AbstractReplyProducingMessageHandler, a base class shared by many such things. Thus if you have a non-void service method, you either have to set an output-channel or a replyChannel header on your messages.

One option suggested by the SI guys is to put a header-enricher in front of your service activator that will set the replyChannel header to "nullChannel". Because headers aren't overwritten by default, any existing replyChannel will work as intended, and everything else will be dumped to the nullChannel.

As for the requires-reply attribute, that's for handling an entirely different problem where you have a component that might produce null instead of a valid messages. That flag allows you to indicate that a null response should be turned into an exception. You'll find a discussion of this in the note on "Messaging Gateway Error Handling" and in "Gateway behavior when no response arrives".