Skip to content

Commit 19f792d

Browse files
committed
Add Coroutines support for WebClient and WebFlux.fn
This commit is the first part of a more complete Coroutines support coming in Spring Framework 5.2. It introduces suspendable Kotlin extensions for Mono based methods in WebFlux classes like WebClient, ServerRequest, ServerResponse as well as a Coroutines router usable via `coRouter { }`. Coroutines extensions use `await` prefix or `AndAwait` suffix, and most are using names close to their Reactive counterparts, except `exchange` in `WebClient.RequestHeadersSpec` which translates to `awaitResponse`. Upcoming expected changes are: - Leverage `Dispatchers.Unconfined` (Kotlin/kotlinx.coroutines#972) - Expose extensions for `Flux` based API (Kotlin/kotlinx.coroutines#254) - Introduce interop with `CoroutineContext` (Kotlin/kotlinx.coroutines#284) - Support Coroutines in `ReactiveAdapterRegistry` - Support Coroutines for WebFlux annotated controllers - Fix return type of Kotlin suspending functions (spring-projectsgh-21058) See spring-projectsgh-19975
1 parent 04bb114 commit 19f792d

16 files changed

+1182
-23
lines changed

spring-webflux/spring-webflux.gradle

+2
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ dependencies {
4040
optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
4141
optional("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
4242
optional("com.google.protobuf:protobuf-java-util:3.6.1")
43+
optional("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.1.1")
44+
optional("org.jetbrains.kotlinx:kotlinx-coroutines-reactor:1.1.1")
4345
testCompile("javax.xml.bind:jaxb-api:2.3.1")
4446
testCompile("com.fasterxml:aalto-xml:1.1.1")
4547
testCompile("org.hibernate:hibernate-validator:6.0.14.Final")

spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt

+29-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.web.reactive.function.client
1818

19+
import kotlinx.coroutines.reactive.awaitSingle
1920
import org.springframework.core.ParameterizedTypeReference
2021
import org.springframework.http.ResponseEntity
2122
import reactor.core.publisher.Flux
@@ -64,3 +65,30 @@ inline fun <reified T : Any> ClientResponse.toEntity(): Mono<ResponseEntity<T>>
6465
*/
6566
inline fun <reified T : Any> ClientResponse.toEntityList(): Mono<ResponseEntity<List<T>>> =
6667
toEntityList(object : ParameterizedTypeReference<T>() {})
68+
69+
/**
70+
* Coroutines variant of [ClientResponse.bodyToMono].
71+
*
72+
* @author Sebastien Deleuze
73+
* @since 5.2
74+
*/
75+
suspend inline fun <reified T : Any> ClientResponse.awaitBody(): T =
76+
bodyToMono<T>().awaitSingle()
77+
78+
/**
79+
* Coroutines variant of [ClientResponse.toEntity].
80+
*
81+
* @author Sebastien Deleuze
82+
* @since 5.2
83+
*/
84+
suspend inline fun <reified T : Any> ClientResponse.awaitEntity(): ResponseEntity<T> =
85+
toEntity<T>().awaitSingle()
86+
87+
/**
88+
* Coroutines variant of [ClientResponse.toEntityList].
89+
*
90+
* @author Sebastien Deleuze
91+
* @since 5.2
92+
*/
93+
suspend inline fun <reified T : Any> ClientResponse.awaitEntityList(): ResponseEntity<List<T>> =
94+
toEntityList<T>().awaitSingle()

spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/WebClientExtensions.kt

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2017 the original author or authors.
2+
* Copyright 2002-2019 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,6 +16,9 @@
1616

1717
package org.springframework.web.reactive.function.client
1818

19+
import kotlinx.coroutines.GlobalScope
20+
import kotlinx.coroutines.reactive.awaitSingle
21+
import kotlinx.coroutines.reactor.mono
1922
import org.reactivestreams.Publisher
2023
import org.springframework.core.ParameterizedTypeReference
2124
import org.springframework.web.reactive.function.client.WebClient.RequestBodySpec
@@ -57,3 +60,30 @@ inline fun <reified T : Any> WebClient.ResponseSpec.bodyToMono(): Mono<T> =
5760
*/
5861
inline fun <reified T : Any> WebClient.ResponseSpec.bodyToFlux(): Flux<T> =
5962
bodyToFlux(object : ParameterizedTypeReference<T>() {})
63+
64+
/**
65+
* Coroutines variant of [WebClient.RequestHeadersSpec.exchange].
66+
*
67+
* @author Sebastien Deleuze
68+
* @since 5.2
69+
*/
70+
suspend fun WebClient.RequestHeadersSpec<out WebClient.RequestHeadersSpec<*>>.awaitResponse(): ClientResponse =
71+
exchange().awaitSingle()
72+
73+
/**
74+
* Coroutines variant of [WebClient.RequestBodySpec.body].
75+
*
76+
* @author Sebastien Deleuze
77+
* @since 5.2
78+
*/
79+
inline fun <reified T: Any> WebClient.RequestBodySpec.body(crossinline supplier: suspend () -> T)
80+
= body(GlobalScope.mono { supplier.invoke() })
81+
82+
/**
83+
* Coroutines variant of [WebClient.ResponseSpec.bodyToMono].
84+
*
85+
* @author Sebastien Deleuze
86+
* @since 5.2
87+
*/
88+
suspend inline fun <reified T : Any> WebClient.ResponseSpec.awaitBody() : T =
89+
bodyToMono<T>().awaitSingle()

0 commit comments

Comments
 (0)