You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/modules/ROOT/pages/spring-cloud-function/programming-model.adoc
+158-12
Original file line number
Diff line number
Diff line change
@@ -705,31 +705,177 @@ However, given that `org.springframework.cloud.function.json.JsonMapper` is also
705
705
[[kotlin-lambda-support]]
706
706
== Kotlin Lambda support
707
707
708
-
We also provide support for Kotlin lambdas (since v2.0).
709
-
Consider the following:
708
+
Spring Cloud Function provides first-class support for Kotlin, allowing developers to leverage idiomatic Kotlin features, including coroutines and Flow, alongside imperative and Reactor-based programming models.
710
709
711
-
[source, java]
710
+
=== Defining Functions in Kotlin
711
+
712
+
You can define Suppliers, Functions, and Consumers in Kotlin and register them as Spring beans using several approaches:
713
+
714
+
* **Kotlin Lambdas:** Define functions directly as lambda expressions within `@Bean` definitions. This is concise for simple functions.
715
+
[source, kotlin]
716
+
----
717
+
@Configuration
718
+
class MyKotlinConfiguration {
719
+
720
+
@Bean
721
+
fun kotlinSupplier(): () -> String = { "Hello from Kotlin Lambda" }
722
+
723
+
@Bean
724
+
fun kotlinFunction(): (String) -> String = { it.uppercase() }
725
+
726
+
@Bean
727
+
fun kotlinConsumer(): (String) -> Unit = { println("Consumed by Kotlin Lambda: $it") }
728
+
}
729
+
----
730
+
731
+
* **Kotlin Classes implementing Kotlin Functional Types:** Define a class that directly implements the desired Kotlin functional type (e.g., `(String) -> String`, `suspend () -> Flow<Int>`).
732
+
[source, kotlin]
733
+
----
734
+
@Component
735
+
class UppercaseFunction : (String) -> String {
736
+
override fun invoke(p1: String): String = p1.uppercase()
737
+
}
738
+
739
+
// Can also be registered via @Bean
740
+
----
741
+
742
+
* **Kotlin Classes implementing `java.util.function` Interfaces:** Define a Kotlin class that implements the standard Java `Supplier`, `Function`, or `Consumer` interfaces.
743
+
[source, kotlin]
744
+
----
745
+
@Component
746
+
class ReverseFunction : Function<String, String> {
747
+
override fun apply(t: String): String = t.reversed()
748
+
}
749
+
----
750
+
751
+
Regardless of the definition style, beans of these types are registered with the `FunctionCatalog`, benefiting from features like type conversion and composition.
752
+
753
+
=== Coroutine Support (`suspend` and `Flow`)
754
+
755
+
A key feature is the seamless integration with Kotlin Coroutines. You can use `suspend` functions and `kotlinx.coroutines.flow.Flow` directly in your function signatures. The framework automatically handles the coroutine context and reactive stream conversions.
756
+
757
+
* **`suspend` Functions:** Functions marked with `suspend` can perform non-blocking operations using coroutine delays or other suspending calls.
758
+
[source, kotlin]
712
759
----
713
760
@Bean
714
-
open fun kotlinSupplier(): () -> String {
715
-
return { "Hello from Kotlin" }
761
+
fun suspendingFunction(): suspend (String) -> Int = {
762
+
delay(100) // Non-blocking delay
763
+
it.length
716
764
}
717
765
718
766
@Bean
719
-
open fun kotlinFunction(): (String) -> String {
720
-
return { it.toUpperCase() }
767
+
fun suspendingSupplier(): suspend () -> String = {
768
+
delay(50)
769
+
"Data from suspend"
721
770
}
722
771
723
772
@Bean
724
-
open fun kotlinConsumer(): (String) -> Unit {
725
-
return { println(it) }
773
+
fun suspendingConsumer(): suspend (String) -> Unit = {
774
+
delay(20)
775
+
println("Suspend consumed: $it")
726
776
}
777
+
----
727
778
779
+
* **`Flow` Integration:** Kotlin `Flow` can be used for reactive stream processing, similar to Reactor's `Flux`.
780
+
[source, kotlin]
728
781
----
729
-
The above represents Kotlin lambdas configured as Spring beans. The signature of each maps to a Java equivalent of `Supplier`, `Function` and `Consumer`, and thus supported/recognized signatures by the framework.
730
-
While mechanics of Kotlin-to-Java mapping are outside of the scope of this documentation, it is important to understand that the same rules for signature transformation outlined in "Java 8 function support" section are applied here as well.
782
+
@Bean
783
+
fun flowFunction(): (Flow<String>) -> Flow<Int> = { flow ->
784
+
flow.map { it.length } // Process the stream reactively
785
+
}
786
+
787
+
@Bean
788
+
fun flowSupplier(): () -> Flow<String> = {
789
+
flow { // kotlinx.coroutines.flow.flow builder
790
+
emit("a")
791
+
delay(10)
792
+
emit("b")
793
+
}
794
+
}
795
+
796
+
// Consumer example taking a Flow
797
+
@Bean
798
+
fun flowConsumer(): suspend (Flow<String>) -> Unit = { flow ->
799
+
flow.collect { item -> // Collect must happen within a coroutine scope
800
+
println("Flow consumed: $item")
801
+
}
802
+
}
803
+
----
804
+
805
+
* **Combining `suspend` and `Flow`:** You can combine `suspend` and `Flow` for complex asynchronous and streaming logic.
806
+
[source, kotlin]
807
+
----
808
+
@Bean
809
+
fun suspendingFlowFunction(): suspend (Flow<String>) -> Flow<String> = { incoming ->
810
+
flow {
811
+
delay(50) // Initial suspend
812
+
incoming.collect {
813
+
emit(it.uppercase()) // Process and emit
814
+
}
815
+
}
816
+
}
817
+
818
+
@Bean
819
+
fun suspendingFlowSupplier(): suspend () -> Flow<Int> = {
820
+
flow {
821
+
repeat(3) {
822
+
delay(100)
823
+
emit(it)
824
+
}
825
+
}
826
+
}
827
+
----
828
+
829
+
=== Reactive Types (`Mono`/`Flux`)
830
+
831
+
Kotlin functions can seamlessly use Reactor's `Mono` and `Flux` types, just like Java functions.
832
+
[source, kotlin]
833
+
----
834
+
@Bean
835
+
fun reactorFunction(): (Flux<String>) -> Mono<Int> = { flux ->
836
+
flux.map { it.length }.reduce(0) { acc, i -> acc + i }
837
+
}
838
+
839
+
@Bean
840
+
fun monoSupplier(): () -> Mono<String> = {
841
+
Mono.just("Reactive Hello")
842
+
}
843
+
----
844
+
845
+
=== `Message<T>` Support
846
+
847
+
Kotlin functions can also operate directly on `org.springframework.messaging.Message<T>` to access headers, including combinations with `suspend` and `Flow`.
848
+
[source, kotlin]
849
+
----
850
+
@Bean
851
+
fun messageFunction(): (Message<String>) -> Message<Int> = { msg ->
852
+
MessageBuilder.withPayload(msg.payload.length)
853
+
.copyHeaders(msg.headers)
854
+
.setHeader("processed", true)
855
+
.build()
856
+
}
857
+
858
+
@Bean
859
+
fun suspendMessageFunction(): suspend (Message<String>) -> Message<String> = { msg ->
To enable Kotlin support all you need is to add Kotlin SDK libraries on the classpath which will trigger appropriate autoconfiguration and supporting classes.
878
+
For a comprehensive set of runnable examples showcasing these Kotlin features, please refer to the `src/test/kotlin/org/springframework/cloud/function/kotlin/arity` directory within the Spring Cloud Function repository. These examples demonstrate a wide range of function signatures with different arities, including regular functions, suspend functions (coroutines), and various reactive types (Flow, Mono, Flux).
0 commit comments