Search code examples
spring-integrationspring-integration-dsl

Spring Integration - how to route based on a header value using the Kotlin DSL


Assuming I've got a header with a property called "count" on it, how do I route based on that value ?

In the Kotlin DSL there is the route function, but I'm unsure how to configure it to be a HeaderValueRouter

The documentation says the following for the Java DSL,but it isn't clear to me how I can get hold of the headers within the router block.

Does anyone have an example (Kotlin and Java DSLs ) ?

Spring Integration natively provides specialized router types, including:

HeaderValueRouter

PayloadTypeRouter

ExceptionTypeRouter

RecipientListRouter

XPathRouter

As with many other DSL IntegrationFlowBuilder EIP methods, the route() method can apply any AbstractMessageRouter implementation or, for convenience, a String as a SpEL expression or a ref-method pair. In addition, you can configure route() with a lambda and use a lambda for a Consumer<RouterSpec>.


Solution

  • Here is a Unit test which demonstrates how your request is possible with Kotlin DSL:

    @SpringJUnitConfig
    @DirtiesContext
    class RouterDslTests {
    
        @Autowired
        @Qualifier("routeByHeader.input")
        private lateinit var routeByHeaderInputChannel: MessageChannel
    
        @Autowired
        private lateinit var fooChannel: PollableChannel
    
        @Autowired
        private lateinit var barChannel: PollableChannel
    
        @Test
        fun `route by header`() {
            var message = MessageBuilder.withPayload("test1")
                .setHeader("my_route", "foo")
                .build()
    
            this.routeByHeaderInputChannel.send(message)
    
            var receive = this.fooChannel.receive(10_000)
            var payload = receive?.payload
            assertThat(payload)
                .isNotNull()
                .isEqualTo("test1")
    
            message = MessageBuilder.withPayload("test2")
                .setHeader("my_route", "bar")
                .build()
    
            this.routeByHeaderInputChannel.send(message)
    
            receive = this.barChannel.receive(10_000)
            payload = receive?.payload
            assertThat(payload)
                .isNotNull()
                .isEqualTo("test2")
        }
    
        @Configuration
        @EnableIntegration
        class Config {
    
            @Bean
            fun routeByHeader() =
                integrationFlow {
                    route<Message<*>, String>({ it.headers["my_route"].toString() }) {
                        suffix("Channel")
                    }
                }
    
            @Bean
            fun fooChannel() = QueueChannel()
    
            @Bean
            fun barChannel() = QueueChannel()
        }
    
    }
    

    What you just need is to enforce a route() function to deal with the whole Message as input. Then you have access to its headers in the lambda.

    This might not be explained in the Kotlin DSL docs, but here is something in Java DSL: https://docs.spring.io/spring-integration/docs/current/reference/html/dsl.html#java-dsl-class-cast