1. Overview
In this tutorial, we’ll learn about the Spring Integration Kotlin DSL. It’s an extension of the Java DSL.
It makes enterprise integration with Kotlin easier and smoother. Practically, we’ll port our file-moving integration to Kotlin.
2. Setup
First, let’s add the Spring Integration Core dependency to our pom.xml:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>6.0.5</version>
</dependency>
It’s also pulled transitively after we add the dependency to Spring Integration File:
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-file</artifactId>
<version>6.0.5</version>
</dependency>
3. Spring Integration Kotlin DSL
Let’s start by reviewing Kotlin DSL building blocks. Then, we’ll use them in our file-moving integration. That integration will move JPEG files from one folder to another.
3.1. Basics
First, we declare Kotlin DSL integration flows using org.springframework.integration.dsl.integrationFlow()**. It’s a set of overloaded functions that produce a standard IntegrationFlow lambda out of a KotlinIntegrationFlowDefinition:
@Bean
fun simpleFlow(): IntegrationFlow {
return integrationFlow {
filter<String> { it === "Spring Integration with Kotlin | Baeldung" }
wireTap {
handle { message -> println(message.payload) }
}
transform<String> { it.uppercase() }
}
}
This integration flow receives messages as input and applies a filter to only allow messages with a specific payload. It then sends a copy of the filtered message to a handler for debugging purposes and transforms the filtered message payload to uppercase. The resulting message is then forwarded to the next component in the integration flow.
Notably, KotlinIntegrationFlowDefinition, provided in a builder style, wraps the classic IntegrationFlowDefinition.
Additionally, overloaded integrationFlow() functions come in handy when we want to supply a source of data:
@Bean
fun mixedFlow(): IntegrationFlow {
return integrationFlow(simpleFlow()) {
channel("baeldung")
transform<String> { it.lowercase() }
}
}
Here, mixedFlow() is built on top of our simpleFlow() integration and changes to lowercase anything coming from the baeldung channel.
Next, integrationFlow() functions interoperate well with Java DSL API that requires reifying.
Finally, integrationFlow() functions guarantee full compatibility with the Java DSL IntegrationFlow.from() API and the Kotlin language structures:
@Bean
fun mixedFlow2(): StandardIntegrationFlow = IntegrationFlow.from(simpleFlow()).channel("baeldung").get()
mixedFlow2() is strictly equivalent to previous mixedFlow().
3.2. Spring Integration File
Now, let’s construct the flow of our file-moving integration example:
@Bean
fun kotlinFileMover(): IntegrationFlow = integrationFlow(sourceDirectory(), { poller { it.fixedDelay(10000) } }) {
filter { message: File -> message.name.endsWith(".jpg") }
handle("targetDirectory")
}
With that, we’ve moved all JPEG files from our source directory to our target directory. The operation happens every 10s.
In the code above, sourceDirectory() returns a MessageSource bean:
@Bean
fun sourceDirectory(): MessageSource<File> {
val messageSource = FileReadingMessageSource()
messageSource.setDirectory(File(inputDir))
return messageSource
}
On the other hand, targetDirectory() returns a MessageHandler bean:
@Bean
fun targetDirectory(): MessageHandler {
val handler = FileWritingMessageHandler(File(outputDir))
handler.setFileExistsMode(FileExistsMode.REPLACE)
handler.setExpectReply(false)
return handler
}
The handler replaces existing files in the target directory. But, it won’t reply to the channel after copy.
4. Conclusion
In this article, we’ve had an overview of Spring Integration Kotlin DSL.
After an initial exploration of the DSL basic features, we looked at its interoperability with the Java DSL API. All of that finally helped us rewrite our file-moving integration.
As always, the code for the examples is available over on GitHub.