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 57b82a88f7..8f60efa9a4 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 @@ -22,8 +22,9 @@ import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.reactive.awaitFirstOrNull import kotlinx.coroutines.reactive.awaitSingle import kotlinx.coroutines.reactive.flow.asFlow -import kotlinx.coroutines.reactive.flow.asPublisher import org.springframework.core.ParameterizedTypeReference +import reactor.core.publisher.Flux +import reactor.core.publisher.Mono import java.net.URI /** @@ -53,16 +54,18 @@ suspend fun RSocketRequester.Builder.connectTcpAndAwait(host: String, port: Int) suspend fun RSocketRequester.Builder.connectWebSocketAndAwait(uri: URI): RSocketRequester = connectWebSocket(uri).awaitSingle() - /** - * Kotlin [Flow] variant of [RSocketRequester.RequestSpec.data]. + * Extension for [RSocketRequester.RequestSpec.data] providing a `data(producer)` + * variant leveraging Kotlin reified type parameters. This extension is not subject to type + * erasure and retains actual generic type arguments. * * @author Sebastien Deleuze * @since 5.2 */ +@Suppress("EXTENSION_SHADOWED_BY_MEMBER") @FlowPreview -fun RSocketRequester.RequestSpec.dataFlow(data: Flow): RSocketRequester.ResponseSpec = - data(data.asPublisher(), object : ParameterizedTypeReference() {}) +fun RSocketRequester.RequestSpec.data(producer: Any): RSocketRequester.ResponseSpec = + data(producer, object : ParameterizedTypeReference() {}) /** * Coroutines variant of [RSocketRequester.ResponseSpec.send]. @@ -92,3 +95,26 @@ suspend fun RSocketRequester.ResponseSpec.retrieveAndAwait(): T = @FlowPreview fun RSocketRequester.ResponseSpec.retrieveFlow(batchSize: Int = 1): Flow = retrieveFlux(object : ParameterizedTypeReference() {}).asFlow(batchSize) + +/** + * Extension for [RSocketRequester.ResponseSpec.retrieveMono] providing a `retrieveMono()` + * variant leveraging Kotlin reified type parameters. This extension is not subject to type + * erasure and retains actual generic type arguments. + * + * @author Sebastien Deleuze + * @since 5.2 + */ +fun RSocketRequester.ResponseSpec.retrieveMono(): Mono = + retrieveMono(object : ParameterizedTypeReference() {}) + + +/** + * Extension for [RSocketRequester.ResponseSpec.retrieveFlux] providing a `retrieveFlux()` + * variant leveraging Kotlin reified type parameters. This extension is not subject to type + * erasure and retains actual generic type arguments. + * + * @author Sebastien Deleuze + * @since 5.2 + */ +fun RSocketRequester.ResponseSpec.retrieveFlux(): Flux = + retrieveFlux(object : ParameterizedTypeReference() {}) diff --git a/spring-messaging/src/test/kotlin/org/springframework/messaging/rsocket/RSocketRequesterExtensionsTests.kt b/spring-messaging/src/test/kotlin/org/springframework/messaging/rsocket/RSocketRequesterExtensionsTests.kt index 9bb7f1a0f6..9750734a8b 100644 --- a/spring-messaging/src/test/kotlin/org/springframework/messaging/rsocket/RSocketRequesterExtensionsTests.kt +++ b/spring-messaging/src/test/kotlin/org/springframework/messaging/rsocket/RSocketRequesterExtensionsTests.kt @@ -3,7 +3,6 @@ package org.springframework.messaging.rsocket import io.mockk.every import io.mockk.mockk import kotlinx.coroutines.FlowPreview -import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.toList import kotlinx.coroutines.runBlocking import org.junit.Assert.assertEquals @@ -54,11 +53,19 @@ class RSocketRequesterExtensionsTests { } @Test - fun dataFlow() { + fun dataFlowWithType() { val requestSpec = mockk() val responseSpec = mockk() every { requestSpec.data(any>(), any>()) } returns responseSpec - assertEquals(responseSpec, requestSpec.dataFlow(mockk>())) + assertEquals(responseSpec, requestSpec.data(mockk())) + } + + @Test + fun dataFlowWithoutType() { + val requestSpec = mockk() + val responseSpec = mockk() + every { requestSpec.data(any()) } returns responseSpec + assertEquals(responseSpec, requestSpec.data(mockk())) } @Test @@ -88,4 +95,22 @@ class RSocketRequesterExtensionsTests { assertEquals(listOf("foo", "bar"), responseSpec.retrieveFlow().toList()) } } + + @Test + fun retrieveMono() { + val responseSpec = mockk() + every { responseSpec.retrieveMono(any>()) } returns Mono.just("foo") + runBlocking { + assertEquals("foo", responseSpec.retrieveMono().block()) + } + } + + @Test + fun retrieveFlux() { + val responseSpec = mockk() + every { responseSpec.retrieveFlux(any>()) } returns Flux.just("foo", "bar") + runBlocking { + assertEquals(listOf("foo", "bar"), responseSpec.retrieveFlux().collectList().block()) + } + } }