Search code examples
javaspring-bootspring-integrationspring-integration-dsl

Spring integration routing with multiple rules


I'm using Spring Integration with DSL and I need to route messages for various channels. Simply put, in case of failure they should go to an output channel, in case of success they should go to one of two channels. Both routings are based on header parameters. I created two routers. One to handle failures and another to handle successes, but when I try to start the application I get the following error:

nested exception is org.springframework.beans.factory.BeanCreationException: The 'currentComponent' (org.springframework.integration.router.MethodInvokingRouter@50ac1249) is a one-way 'MessageHandler' and it isn't appropriate to configure 'failure-channel'. This is the end of the integration flow. 

My flow definition

@Bean
public IntegrationFlow myFlow() {
    return IntegrationFlows.from("from")
        .route(Message.class,
            message -> message
                .getHeaders().containsKey("FAILURE"),
            mapping -> mapping
                .channelMapping(true, "failure-channel"))
        .route(Message.class,
            message -> message
                .getHeaders().get("NEXT"),
            mapping -> mapping
                .channelMapping("first", "first-channel")
                .channelMapping("second", "second-channel")
        .get();
}

How can I implement this logic? As far as I read in the documentation, there's no problem in having more than one route defined and both conditions are valid in isolation, since to have it working I created another channel that receives the successes and only does the second routing.

I'm assuming the problem is because the first router consumes the message, but I was looking for a behaviour similar to if route A does not resolve go to route B.


Solution

  • See RouterSpec:

    /**
     * Make a default output mapping of the router to the parent flow.
     * Use the next, after router, parent flow {@link MessageChannel} as a
     * {@link AbstractMessageRouter#setDefaultOutputChannel(MessageChannel)} of this router.
     * @return the router spec.
     */
    public S defaultOutputToParentFlow() {
    

    And there is also a note in the docs: https://docs.spring.io/spring-integration/docs/current/reference/html/dsl.html#java-dsl-routers

    The .defaultOutputToParentFlow() of the .routeToRecipients() definition lets you set the router’s defaultOutput as a gateway to continue a process for the unmatched messages in the main flow.

    So, your first router without a FAILURE header is going to send its output to the main flow for desired NEXT router.