diff --git a/build.gradle b/build.gradle index ce4df66b71a1..ed78274509f7 100644 --- a/build.gradle +++ b/build.gradle @@ -32,7 +32,7 @@ configure(allprojects) { project -> mavenBom "io.rsocket:rsocket-bom:1.1.0-RC1" mavenBom "org.eclipse.jetty:jetty-bom:9.4.32.v20200930" mavenBom "org.jetbrains.kotlin:kotlin-bom:1.4.10" - mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.3.9" + mavenBom "org.jetbrains.kotlinx:kotlinx-coroutines-bom:1.4.0-M1" mavenBom "org.junit:junit-bom:5.7.0" } dependencies { diff --git a/spring-core/kotlin-coroutines/src/main/kotlin/org/springframework/core/CoroutinesUtils.kt b/spring-core/kotlin-coroutines/src/main/kotlin/org/springframework/core/CoroutinesUtils.kt index 04a3817278c8..cfde83920127 100644 --- a/spring-core/kotlin-coroutines/src/main/kotlin/org/springframework/core/CoroutinesUtils.kt +++ b/spring-core/kotlin-coroutines/src/main/kotlin/org/springframework/core/CoroutinesUtils.kt @@ -22,7 +22,7 @@ import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.async import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactive.awaitSingleOrNull import kotlinx.coroutines.reactor.asFlux import kotlinx.coroutines.reactor.mono @@ -49,7 +49,7 @@ internal fun deferredToMono(source: Deferred) = * @since 5.2 */ internal fun monoToDeferred(source: Mono) = - GlobalScope.async(Dispatchers.Unconfined) { source.awaitFirstOrNull() } + GlobalScope.async(Dispatchers.Unconfined) { source.awaitSingleOrNull() } /** * Invoke a suspending function and converts it to [Mono] or [reactor.core.publisher.Flux]. diff --git a/spring-messaging/src/main/kotlin/org/springframework/messaging/rsocket/RSocketRequesterExtensions.kt b/spring-messaging/src/main/kotlin/org/springframework/messaging/rsocket/RSocketRequesterExtensions.kt index 687a94a67fe2..4cddee446856 100644 --- a/spring-messaging/src/main/kotlin/org/springframework/messaging/rsocket/RSocketRequesterExtensions.kt +++ b/spring-messaging/src/main/kotlin/org/springframework/messaging/rsocket/RSocketRequesterExtensions.kt @@ -19,7 +19,7 @@ package org.springframework.messaging.rsocket import io.rsocket.transport.ClientTransport import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.reactive.asFlow -import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactive.awaitSingleOrNull import kotlinx.coroutines.reactive.awaitSingle import org.reactivestreams.Publisher import org.springframework.core.ParameterizedTypeReference @@ -103,7 +103,7 @@ inline fun RSocketRequester.RequestSpec.dataWithType(flow: Flo * @since 5.2 */ suspend fun RSocketRequester.RetrieveSpec.sendAndAwait() { - send().awaitFirstOrNull() + send().awaitSingleOrNull() } /** @@ -122,7 +122,7 @@ suspend inline fun RSocketRequester.RetrieveSpec.retrieveAndAw * @since 5.2.1 */ suspend inline fun RSocketRequester.RetrieveSpec.retrieveAndAwaitOrNull(): T? = - retrieveMono(object : ParameterizedTypeReference() {}).awaitFirstOrNull() + retrieveMono(object : ParameterizedTypeReference() {}).awaitSingleOrNull() /** * Coroutines variant of [RSocketRequester.RetrieveSpec.retrieveFlux]. diff --git a/spring-r2dbc/src/main/kotlin/org/springframework/r2dbc/core/DatabaseClientExtensions.kt b/spring-r2dbc/src/main/kotlin/org/springframework/r2dbc/core/DatabaseClientExtensions.kt index 0528f2c76f95..a6013f41ea9e 100644 --- a/spring-r2dbc/src/main/kotlin/org/springframework/r2dbc/core/DatabaseClientExtensions.kt +++ b/spring-r2dbc/src/main/kotlin/org/springframework/r2dbc/core/DatabaseClientExtensions.kt @@ -16,7 +16,7 @@ package org.springframework.r2dbc.core -import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactive.awaitSingleOrNull /** * Coroutines variant of [DatabaseClient.GenericExecuteSpec.then]. @@ -24,7 +24,7 @@ import kotlinx.coroutines.reactive.awaitFirstOrNull * @author Sebastien Deleuze */ suspend fun DatabaseClient.GenericExecuteSpec.await() { - then().awaitFirstOrNull() + then().awaitSingleOrNull() } /** diff --git a/spring-r2dbc/src/main/kotlin/org/springframework/r2dbc/core/RowsFetchSpecExtensions.kt b/spring-r2dbc/src/main/kotlin/org/springframework/r2dbc/core/RowsFetchSpecExtensions.kt index d79d954c0706..8921dd36a39a 100644 --- a/spring-r2dbc/src/main/kotlin/org/springframework/r2dbc/core/RowsFetchSpecExtensions.kt +++ b/spring-r2dbc/src/main/kotlin/org/springframework/r2dbc/core/RowsFetchSpecExtensions.kt @@ -17,7 +17,7 @@ package org.springframework.r2dbc.core import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.reactive.asFlow -import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactive.awaitSingleOrNull import org.springframework.dao.EmptyResultDataAccessException /** @@ -26,7 +26,7 @@ import org.springframework.dao.EmptyResultDataAccessException * @author Sebastien Deleuze */ suspend fun RowsFetchSpec.awaitOne(): T { - return one().awaitFirstOrNull() ?: throw EmptyResultDataAccessException(1) + return one().awaitSingleOrNull() ?: throw EmptyResultDataAccessException(1) } /** @@ -35,15 +35,15 @@ suspend fun RowsFetchSpec.awaitOne(): T { * @author Sebastien Deleuze */ suspend fun RowsFetchSpec.awaitOneOrNull(): T? = - one().awaitFirstOrNull() + one().awaitSingleOrNull() /** * Non-nullable Coroutines variant of [RowsFetchSpec.first]. * * @author Sebastien Deleuze */ -suspend fun RowsFetchSpec.awaitFirst(): T { - return first().awaitFirstOrNull() ?: throw EmptyResultDataAccessException(1) +suspend fun RowsFetchSpec.awaitSingle(): T { + return first().awaitSingleOrNull() ?: throw EmptyResultDataAccessException(1) } /** @@ -51,8 +51,8 @@ suspend fun RowsFetchSpec.awaitFirst(): T { * * @author Sebastien Deleuze */ -suspend fun RowsFetchSpec.awaitFirstOrNull(): T? = - first().awaitFirstOrNull() +suspend fun RowsFetchSpec.awaitSingleOrNull(): T? = + first().awaitSingleOrNull() /** * Coroutines [Flow] variant of [RowsFetchSpec.all]. diff --git a/spring-r2dbc/src/test/kotlin/org/springframework/r2dbc/core/RowsFetchSpecExtensionsTests.kt b/spring-r2dbc/src/test/kotlin/org/springframework/r2dbc/core/RowsFetchSpecExtensionsTests.kt index 3146db956cc8..e3a8003cfe17 100644 --- a/spring-r2dbc/src/test/kotlin/org/springframework/r2dbc/core/RowsFetchSpecExtensionsTests.kt +++ b/spring-r2dbc/src/test/kotlin/org/springframework/r2dbc/core/RowsFetchSpecExtensionsTests.kt @@ -98,7 +98,7 @@ class RowsFetchSpecExtensionsTests { every { spec.first() } returns Mono.just("foo") runBlocking { - assertThat(spec.awaitFirst()).isEqualTo("foo") + assertThat(spec.awaitSingle()).isEqualTo("foo") } verify { @@ -112,7 +112,7 @@ class RowsFetchSpecExtensionsTests { every { spec.first() } returns Mono.empty() assertThatExceptionOfType(EmptyResultDataAccessException::class.java).isThrownBy { - runBlocking { spec.awaitFirst() } + runBlocking { spec.awaitSingle() } } verify { @@ -121,12 +121,12 @@ class RowsFetchSpecExtensionsTests { } @Test - fun awaitFirstOrNullWithValue() { + fun awaitSingleOrNullWithValue() { val spec = mockk>() every { spec.first() } returns Mono.just("foo") runBlocking { - assertThat(spec.awaitFirstOrNull()).isEqualTo("foo") + assertThat(spec.awaitSingleOrNull()).isEqualTo("foo") } verify { @@ -135,12 +135,12 @@ class RowsFetchSpecExtensionsTests { } @Test - fun awaitFirstOrNullWithNull() { + fun awaitSingleOrNullWithNull() { val spec = mockk>() every { spec.first() } returns Mono.empty() runBlocking { - assertThat(spec.awaitFirstOrNull()).isNull() + assertThat(spec.awaitSingleOrNull()).isNull() } verify { diff --git a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt index 5f20f4b3e40b..9e2984cecbe9 100644 --- a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt +++ b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/ClientResponseExtensions.kt @@ -17,7 +17,7 @@ package org.springframework.web.reactive.function.client import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactive.awaitSingleOrNull import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactive.asFlow import org.springframework.core.ParameterizedTypeReference @@ -115,7 +115,7 @@ suspend fun ClientResponse.awaitBody(clazz: KClass): T = * @since 5.2 */ suspend inline fun ClientResponse.awaitBodyOrNull(): T? = - bodyToMono().awaitFirstOrNull() + bodyToMono().awaitSingleOrNull() /** * `KClass` nullable coroutines variant of [ClientResponse.bodyToMono]. @@ -125,7 +125,7 @@ suspend inline fun ClientResponse.awaitBodyOrNull(): T? = * @since 5.3 */ suspend fun ClientResponse.awaitBodyOrNull(clazz: KClass): T? = - bodyToMono(clazz.java).awaitFirstOrNull() + bodyToMono(clazz.java).awaitSingleOrNull() /** * Coroutines variant of [ClientResponse.toEntity]. diff --git a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/WebClientExtensions.kt b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/WebClientExtensions.kt index 2b8e18d0c3ba..b773e06e302b 100644 --- a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/WebClientExtensions.kt +++ b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/client/WebClientExtensions.kt @@ -19,7 +19,7 @@ package org.springframework.web.reactive.function.client import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.reactive.asFlow -import kotlinx.coroutines.reactive.awaitFirst +import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactor.asFlux import kotlinx.coroutines.reactor.mono @@ -87,7 +87,7 @@ suspend fun RequestHeadersSpec>.awaitExchange(): Clien * @since 5.3 */ suspend fun RequestHeadersSpec>.awaitExchange(responseHandler: suspend (ClientResponse) -> T): T = - exchangeToMono { mono(Dispatchers.Unconfined) { responseHandler.invoke(it) } }.awaitFirst() + exchangeToMono { mono(Dispatchers.Unconfined) { responseHandler.invoke(it) } }.awaitSingle() /** * Coroutines variant of [WebClient.RequestHeadersSpec.exchangeToFlux]. diff --git a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/CoRouterFunctionDsl.kt b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/CoRouterFunctionDsl.kt index f045c18182b7..6974faee6d6b 100644 --- a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/CoRouterFunctionDsl.kt +++ b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/CoRouterFunctionDsl.kt @@ -17,7 +17,7 @@ package org.springframework.web.reactive.function.server import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.reactive.awaitFirst +import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactor.mono import org.springframework.core.io.Resource import org.springframework.http.HttpMethod @@ -532,7 +532,7 @@ class CoRouterFunctionDsl internal constructor (private val init: (CoRouterFunct builder.filter { serverRequest, handlerFunction -> mono(Dispatchers.Unconfined) { filterFunction(serverRequest) { - handlerFunction.handle(serverRequest).awaitFirst() + handlerFunction.handle(serverRequest).awaitSingle() } } } diff --git a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt index 42b877be309b..f1a93816ef44 100644 --- a/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt +++ b/spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt @@ -17,7 +17,7 @@ package org.springframework.web.reactive.function.server import kotlinx.coroutines.flow.Flow -import kotlinx.coroutines.reactive.awaitFirstOrNull +import kotlinx.coroutines.reactive.awaitSingleOrNull import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactive.asFlow import org.springframework.core.ParameterizedTypeReference @@ -99,7 +99,7 @@ suspend fun ServerRequest.awaitBody(clazz: KClass): T = * @since 5.2 */ suspend inline fun ServerRequest.awaitBodyOrNull(): T? = - bodyToMono().awaitFirstOrNull() + bodyToMono().awaitSingleOrNull() /** * `KClass` nullable Coroutines variant of [ServerRequest.bodyToMono]. @@ -109,7 +109,7 @@ suspend inline fun ServerRequest.awaitBodyOrNull(): T? = * @since 5.3 */ suspend fun ServerRequest.awaitBodyOrNull(clazz: KClass): T? = - bodyToMono(clazz.java).awaitFirstOrNull() + bodyToMono(clazz.java).awaitSingleOrNull() /** * Coroutines variant of [ServerRequest.formData]. @@ -136,7 +136,7 @@ suspend fun ServerRequest.awaitMultipartData(): MultiValueMap = * @since 5.2 */ suspend fun ServerRequest.awaitPrincipal(): Principal? = - principal().awaitFirstOrNull() + principal().awaitSingleOrNull() /** * Coroutines variant of [ServerRequest.session]. diff --git a/src/docs/asciidoc/data-access.adoc b/src/docs/asciidoc/data-access.adoc index bf017a65c50f..cd9f1c9fcaaa 100644 --- a/src/docs/asciidoc/data-access.adoc +++ b/src/docs/asciidoc/data-access.adoc @@ -6749,7 +6749,7 @@ The following query gets the `id` and `name` columns from a table: .Kotlin ---- val first = client.sql("SELECT id, name FROM person") - .fetch().awaitFirst() + .fetch().awaitSingle() ---- The following query uses a bind variable: @@ -6766,7 +6766,7 @@ The following query uses a bind variable: ---- val first = client.sql("SELECT id, name FROM person WHERE WHERE first_name = :fn") .bind("fn", "Joe") - .fetch().awaitFirst() + .fetch().awaitSingle() ---- You might have noticed the use of `fetch()` in the example above. `fetch()` is a @@ -6776,7 +6776,7 @@ Calling `first()` returns the first row from the result and discards remaining r You can consume data with the following operators: * `first()` return the first row of the entire result. Its Kotlin Coroutine variant -is named `awaitFirst()` for non-nullable return values and `awaitFirstOrNull()` +is named `awaitSingle()` for non-nullable return values and `awaitSingleOrNull()` if the value is optional. * `one()` returns exactly one result and fails if the result contains more rows. Using Kotlin Coroutines, `awaitOne()` for exactly one value or `awaitOneOrNull()` diff --git a/src/docs/asciidoc/languages/kotlin.adoc b/src/docs/asciidoc/languages/kotlin.adoc index eeda18601f77..1581546641bb 100644 --- a/src/docs/asciidoc/languages/kotlin.adoc +++ b/src/docs/asciidoc/languages/kotlin.adoc @@ -434,7 +434,7 @@ dependencies { } ---- -Version `1.3.9` and above are supported. +Version `1.4.0-M1` and above are supported. === How Reactive translates to Coroutines? diff --git a/src/docs/asciidoc/rsocket.adoc b/src/docs/asciidoc/rsocket.adoc index 03fc05719df5..97bf16736ccd 100644 --- a/src/docs/asciidoc/rsocket.adoc +++ b/src/docs/asciidoc/rsocket.adoc @@ -601,7 +601,7 @@ Then start an RSocket server through the Java RSocket API and plug the val server = RSocketServer.create(handler.responder()) .bind(TcpServerTransport.create("localhost", 7000)) - .awaitFirst() + .awaitSingle() ---- `RSocketMessageHandler` supports diff --git a/src/docs/asciidoc/web/webflux-functional.adoc b/src/docs/asciidoc/web/webflux-functional.adoc index cc52408082d3..9d504c0bc883 100644 --- a/src/docs/asciidoc/web/webflux-functional.adoc +++ b/src/docs/asciidoc/web/webflux-functional.adoc @@ -172,7 +172,7 @@ Flux people = request.body(BodyExtractors.toFlux(Person.class)); [source,kotlin,role="secondary"] .Kotlin ---- - val string = request.body(BodyExtractors.toMono(String::class.java)).awaitFirst() + val string = request.body(BodyExtractors.toMono(String::class.java)).awaitSingle() val people = request.body(BodyExtractors.toFlux(Person::class.java)).asFlow() ----