Skip to content

Document Kotlin DSL #3210

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 10, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,9 @@ import org.springframework.integration.annotation.Transformer
import org.springframework.integration.channel.DirectChannel
import org.springframework.integration.channel.QueueChannel
import org.springframework.integration.config.EnableIntegration
import org.springframework.integration.dsl.IntegrationFlows
import org.springframework.integration.dsl.integrationFlow
import org.springframework.integration.endpoint.SourcePollingChannelAdapter
import org.springframework.integration.gateway.GatewayProxyFactoryBean
import org.springframework.integration.test.util.OnlyOnceTrigger
import org.springframework.messaging.Message
import org.springframework.messaging.MessageChannel
import org.springframework.messaging.PollableChannel
Expand Down
2 changes: 2 additions & 0 deletions src/reference/asciidoc/dsl.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

The Spring Integration Java configuration and DSL provides a set of convenient builders and a fluent API that lets you configure Spring Integration message flows from Spring `@Configuration` classes.

(See also <<./kotlin-dsl.adoc#kotlin-dsl,Kotlin DSL>>.)

The Java DSL for Spring Integration is essentially a facade for Spring Integration.
The DSL provides a simple way to embed Spring Integration Message Flows into your application by using the fluent `Builder` pattern together with existing Java configuration from Spring Framework and Spring Integration.
We also use and support lambdas (available with Java 8) to further simplify Java configuration.
Expand Down
96 changes: 96 additions & 0 deletions src/reference/asciidoc/kotlin-dsl.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
[[kotlin-dsl]]
== Kotlin DSL

The Kotlin DSL is a wrapper and extension to <<./dsl.adoc#java-dsl,Java DSL>> and aimed to make Spring Integration development on Kotlin as smooth and straightforward as possible with interoperability with the existing Java API and Kotlin language-specific structures.

All you need to get started is just an import for `org.springframework.integration.dsl.integrationFlow` - an overloaded global function for Kotlin DSL.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
All you need to get started is just an import for `org.springframework.integration.dsl.integrationFlow` - an overloaded global function for Kotlin DSL.
All you need to get started is just an import for `org.springframework.integration.dsl.kotlin.integrationFlow` - an overloaded global function for Kotlin DSL.


For `IntegrationFlow` definitions as lambdas we typically don't need anything else from Kotlin and just declare a bean like this:

====
[source, kotlin]
----
@Bean
fun oddFlow() =
IntegrationFlow { flow ->
flow.handle<Any> { _, _ -> "odd" }
}
----
====

In this case Kotlin understands that the lambda should be translated into `IntegrationFlow` anonymous instance and target Java DSL processor parses this construction properly into Java objects.

As an alternative to the construction above and for consistency with use-cases explained below, a Kotlin-specif DSL should be used for declaring integration flows in the *builder* pattern style:

====
[source, kotlin]
----
@Bean
fun flowLambda() =
integrationFlow {
filter<String> { it === "test" }
wireTap {
handle { println(it.payload) }
}
transform<String, String> { it.toUpperCase() }
}
----
====

Such a global `integrationFlow()` function expects a lambda in builder style for a `KotlinIntegrationFlowDefinition` (a Kotlin wrapper for the `IntegrationFlowDefinition`) and produces a regular `IntegrationFlow` lambda implementation.
See more overloaded `integrationFlow()` variants below.

Many other scenarios require an `IntegrationFlow` to be started from source of data (e.g. `JdbcPollingChannelAdapter`, `JmsInboundGateway` or just an existing `MessageChannel`).
For this purpose, the Spring Integration Java DSL provides an `IntegrationFlows` factory with its large number of overloaded `from()` methods.
This factory can be used in Kotlin as well:

====
[source, kotlin]
----
@Bean
fun flowFromSupplier() =
IntegrationFlows.from<String>({ "bar" }) { e -> e.poller { p -> p.fixedDelay(10).maxMessagesPerPoll(1) } }
.channel { c -> c.queue("fromSupplierQueue") }
.get()
----
====

But unfortunately not all `from()` methods are compatible with Kotlin structures.
To fix the gap, this project provides a Kotlin DSL around an `IntegrationFlows` factory.
It is implemented as a set of overloaded `integrationFlow()` functions.
With a consumer for a `KotlinIntegrationFlowDefinition` to declare the rest of the flow as an `IntegrationFlow` lambda to reuse the mentioned above experience and also avoid `get()` call in the end.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
With a consumer for a `KotlinIntegrationFlowDefinition` to declare the rest of the flow as an `IntegrationFlow` lambda to reuse the mentioned above experience and also avoid `get()` call in the end.
With a consumer for a `KotlinIntegrationFlowDefinition`, to declare the rest of the flow as an `IntegrationFlow` lambda to reuse the mentioned above experience; unlike the Java DSL, it also avoids the need for a `get()` call at the end of the flow.

For example:

====
[source, kotlin]
----
@Bean
fun functionFlow() =
integrationFlow<Function<String, String>>({ beanName("functionGateway") }) {
transform<String, String> { it.toUpperCase() }
}

@Bean
fun messageSourceFlow() =
integrationFlow(MessageProcessorMessageSource { "testSource" },
{ poller { it.fixedDelay(10).maxMessagesPerPoll(1) } }) {
channel { queue("fromSupplierQueue") }
}
----
====

In addition, Kotlin extensions are provided for the Java DSL API which needs some refinement for Kotlin structures.
For example `IntegrationFlowDefinition<*>` requires a reifying for many methods with `Class<P>` argument:

====
[source, kotlin]
----
@Bean
fun convertFlow() =
integrationFlow("convertFlowInput") {
convert<TestPojo>()
}
----
====


6 changes: 6 additions & 0 deletions src/reference/asciidoc/whats-new.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ A new `IntegrationFlowExtension` API has been introduced to allow extension of t
This also can be used to introduce customizers for any out-of-the-box `IntegrationComponentSpec` extensions.
See <<./dsl.adoc#java-dsl-extensions,DSL Extensions>> for more information.

[[x5.3-kotlin-dsl]]
==== Kotlin DSL

The Kotlin DSL for integration flow configurations has been introduced.
See <<./kotlin-dsl.adoc#kotlin-dsl,Kotlin DSL Chapter>> for more information.

[[x5.3-reactive-request-handler-advice]]
==== ReactiveRequestHandlerAdvice

Expand Down