Skip to content

Commit 32a3fdd

Browse files
committed
Merge remote-tracking branch 'origin/main'
2 parents 09eff58 + c424ecd commit 32a3fdd

File tree

176 files changed

+8682
-540
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

176 files changed

+8682
-540
lines changed

.github/dependabot.yml

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# To get started with Dependabot version updates, you'll need to specify which
2+
# package ecosystems to update and where the package manifests are located.
3+
# Please see the documentation for all configuration options:
4+
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
5+
6+
version: 2
7+
updates:
8+
- package-ecosystem: "github-actions"
9+
directory: "/"
10+
target-branch: "main"
11+
schedule:
12+
interval: "weekly"
13+
- package-ecosystem: maven
14+
directory: /
15+
schedule:
16+
interval: daily
17+
target-branch: main
18+
# ignore:
19+
# only upgrade by minor or patch
20+
# - dependency-name: "*"
21+
# update-types:
22+
# - version-update:semver-major
23+
- package-ecosystem: maven
24+
directory: /
25+
schedule:
26+
interval: daily
27+
target-branch: 4.3.x
28+
ignore:
29+
# only upgrade by minor or patch
30+
- dependency-name: "*"
31+
update-types:
32+
- version-update:semver-major
33+
- version-update:semver-minor
34+
- package-ecosystem: maven
35+
directory: /
36+
schedule:
37+
interval: daily
38+
target-branch: 4.2.x
39+
ignore:
40+
# only upgrade by minor or patch
41+
- dependency-name: "*"
42+
update-types:
43+
- version-update:semver-major
44+
- version-update:semver-minor
45+
- package-ecosystem: maven
46+
directory: /
47+
schedule:
48+
interval: daily
49+
target-branch: 4.1.x
50+
ignore:
51+
# only upgrade by minor or patch
52+
- dependency-name: "*"
53+
update-types:
54+
- version-update:semver-major
55+
- version-update:semver-minor
56+
- package-ecosystem: npm
57+
target-branch: docs-build
58+
directory: /
59+
schedule:
60+
interval: weekly
61+
- package-ecosystem: npm
62+
target-branch: main
63+
directory: /docs
64+
schedule:
65+
interval: weekly
66+
- package-ecosystem: npm
67+
target-branch: 4.2.x
68+
directory: /docs
69+
schedule:
70+
interval: weekly
71+
- package-ecosystem: npm
72+
target-branch: 4.2.x
73+
directory: /docs
74+
schedule:
75+
interval: weekly
76+
- package-ecosystem: npm
77+
target-branch: 4.1.x
78+
directory: /docs
79+
schedule:
80+
interval: weekly

docs/modules/ROOT/pages/spring-cloud-function/programming-model.adoc

Lines changed: 158 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -705,31 +705,177 @@ However, given that `org.springframework.cloud.function.json.JsonMapper` is also
705705
[[kotlin-lambda-support]]
706706
== Kotlin Lambda support
707707

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.
710709

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]
712759
----
713760
@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
716764
}
717765
718766
@Bean
719-
open fun kotlinFunction(): (String) -> String {
720-
return { it.toUpperCase() }
767+
fun suspendingSupplier(): suspend () -> String = {
768+
delay(50)
769+
"Data from suspend"
721770
}
722771
723772
@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")
726776
}
777+
----
727778

779+
* **`Flow` Integration:** Kotlin `Flow` can be used for reactive stream processing, similar to Reactor's `Flux`.
780+
[source, kotlin]
728781
----
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 ->
860+
delay(100)
861+
MessageBuilder.withPayload(msg.payload.reversed())
862+
.copyHeaders(msg.headers)
863+
.build()
864+
}
865+
866+
@Bean
867+
fun flowMessageFunction(): (Flow<Message<String>>) -> Flow<Message<Int>> = { flow ->
868+
flow.map { msg ->
869+
MessageBuilder.withPayload(msg.payload.hashCode())
870+
.copyHeaders(msg.headers)
871+
.build()
872+
}
873+
}
874+
----
875+
876+
=== Kotlin Sample Project
731877

732-
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).
733879

734880
[[function-component-scan]]
735881
== Function Component Scan

docs/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
<parent>
99
<groupId>org.springframework.cloud</groupId>
1010
<artifactId>spring-cloud-function-parent</artifactId>
11-
<version>4.3.1-SNAPSHOT</version>
11+
<version>5.0.0-SNAPSHOT</version>
1212
</parent>
1313
<packaging>jar</packaging>
1414
<name>Spring Cloud Function Docs</name>

pom.xml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,15 @@
66

77
<artifactId>spring-cloud-function-parent</artifactId>
88
<name>Spring Cloud Function Parent</name>
9-
<version>4.3.1-SNAPSHOT</version>
9+
<version>5.0.0-SNAPSHOT</version>
1010
<description>Spring Cloud Function Parent</description>
1111
<packaging>pom</packaging>
1212
<url>https://github.com/spring-cloud/spring-cloud-function</url>
1313

1414
<parent>
1515
<groupId>org.springframework.cloud</groupId>
1616
<artifactId>spring-cloud-build</artifactId>
17-
<version>4.3.1-SNAPSHOT</version>
17+
<version>5.0.0-SNAPSHOT</version>
1818
<relativePath/>
1919
</parent>
2020

@@ -86,6 +86,10 @@
8686
<argLine>--add-opens java.base/java.util=ALL-UNNAMED</argLine>
8787
</configuration>
8888
</plugin>
89+
<plugin>
90+
<groupId>org.codehaus.mojo</groupId>
91+
<artifactId>flatten-maven-plugin</artifactId>
92+
</plugin>
8993
</plugins>
9094
<pluginManagement>
9195
<plugins>

spring-cloud-function-adapters/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
<parent>
1111
<groupId>org.springframework.cloud</groupId>
1212
<artifactId>spring-cloud-function-parent</artifactId>
13-
<version>4.3.1-SNAPSHOT</version>
13+
<version>5.0.0-SNAPSHOT</version>
1414
</parent>
1515

1616
<name>spring-cloud-function-adapter-parent</name>

spring-cloud-function-adapters/spring-cloud-function-adapter-aws/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
<parent>
1414
<groupId>org.springframework.cloud</groupId>
1515
<artifactId>spring-cloud-function-adapter-parent</artifactId>
16-
<version>4.3.1-SNAPSHOT</version>
16+
<version>5.0.0-SNAPSHOT</version>
1717
</parent>
1818

1919
<properties>

spring-cloud-function-adapters/spring-cloud-function-adapter-aws/src/main/java/org/springframework/cloud/function/adapter/aws/CustomRuntimeEventLoop.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@ private Context generateClientContext(HttpHeaders headers) {
179179
@Override
180180
public int getRemainingTimeInMillis() {
181181
long now = System.currentTimeMillis();
182-
if (!headers.containsKey("Lambda-Runtime-Deadline-Ms")) {
182+
if (!headers.containsHeader("Lambda-Runtime-Deadline-Ms")) {
183183
return 0;
184184
}
185185
int delta = (int) (Long.parseLong(headers.getFirst("Lambda-Runtime-Deadline-Ms")) - now);

spring-cloud-function-adapters/spring-cloud-function-adapter-azure-web/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<parent>
1010
<groupId>org.springframework.cloud</groupId>
1111
<artifactId>spring-cloud-function-adapter-parent</artifactId>
12-
<version>4.3.1-SNAPSHOT</version>
12+
<version>5.0.0-SNAPSHOT</version>
1313
</parent>
1414
<properties>
1515
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

spring-cloud-function-adapters/spring-cloud-function-adapter-azure/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
<parent>
1313
<groupId>org.springframework.cloud</groupId>
1414
<artifactId>spring-cloud-function-adapter-parent</artifactId>
15-
<version>4.3.1-SNAPSHOT</version>
15+
<version>5.0.0-SNAPSHOT</version>
1616
</parent>
1717

1818
<properties>

spring-cloud-function-adapters/spring-cloud-function-adapter-gcp/pom.xml

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
<parent>
1212
<artifactId>spring-cloud-function-adapter-parent</artifactId>
1313
<groupId>org.springframework.cloud</groupId>
14-
<version>4.3.1-SNAPSHOT</version>
14+
<version>5.0.0-SNAPSHOT</version>
1515
</parent>
1616

1717
<properties>
@@ -74,5 +74,15 @@
7474
<version>0.1.2</version>
7575
<scope>test</scope>
7676
</dependency>
77+
<dependency>
78+
<groupId>org.springframework.boot</groupId>
79+
<artifactId>spring-boot-restclient</artifactId>
80+
<scope>test</scope>
81+
</dependency>
82+
<dependency>
83+
<groupId>org.springframework.boot</groupId>
84+
<artifactId>spring-boot-webclient</artifactId>
85+
<scope>test</scope>
86+
</dependency>
7787
</dependencies>
7888
</project>

0 commit comments

Comments
 (0)