From 04e21f70edc35f8baa97770faf243707367029cf Mon Sep 17 00:00:00 2001 From: wushiyuanmaimob Date: Mon, 25 May 2026 17:45:36 +0800 Subject: [PATCH] Preserve generic type info in awaitEntity() awaitEntity() used T::class.java which erases generic type information (e.g. List becomes just List). Use the reified toEntity() extension instead, which preserves full generic type via ParameterizedTypeReference. Closes gh-36770 Signed-off-by: wushiyuanmaimob Assisted-by: Claude Code Signed-off-by: wushiyuanmaimob --- .../reactive/function/client/WebClientExtensions.kt | 2 +- .../function/client/WebClientExtensionsTests.kt | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) 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 c426db2aabcb..f82753286583 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 @@ -236,7 +236,7 @@ inline fun WebClient.ResponseSpec.toEntityFlux(): Mono WebClient.ResponseSpec.awaitEntity(): ResponseEntity { val context = currentCoroutineContext().minusKey(Job.Key) return withContext(context.toReactorContext()) { - toEntity(T::class.java).awaitSingle() + toEntity().awaitSingle() } } diff --git a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/client/WebClientExtensionsTests.kt b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/client/WebClientExtensionsTests.kt index 78943f1013c2..5262e4d97aaf 100644 --- a/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/client/WebClientExtensionsTests.kt +++ b/spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/client/WebClientExtensionsTests.kt @@ -219,6 +219,14 @@ class WebClientExtensionsTests { verify { responseSpec.toEntityFlux(object : ParameterizedTypeReference>() {}) } } + @Test + suspend fun `awaitEntity preserves generic type information`() { + val spec = mockk() + val entity = mockk>>() + every { spec.toEntity(any>>()) } returns Mono.just(entity) + assertThat(spec.awaitEntity>()).isEqualTo(entity) + } + @Test fun `ResponseSpec#awaitEntity with coroutine context propagation`() { val exchangeFunction = mockk() @@ -230,7 +238,7 @@ class WebClientExtensionsTests { every { mockResponse.statusCode() } returns HttpStatus.OK every { mockResponse.headers() } returns mockClientHeaders every { mockClientHeaders.asHttpHeaders() } returns HttpHeaders() - every { mockResponse.bodyToMono(Foo::class.java) } returns Mono.just(foo) + every { mockResponse.bodyToMono(any>()) } returns Mono.just(foo) runBlocking(FooContextElement(foo)) { val responseEntity = WebClient.builder() .exchangeFunction(exchangeFunction) @@ -258,7 +266,7 @@ class WebClientExtensionsTests { every { mockResponse.statusCode() } returns HttpStatus.OK every { mockResponse.headers() } returns mockClientHeaders every { mockClientHeaders.asHttpHeaders() } returns HttpHeaders() - every { mockResponse.bodyToMono(Foo::class.java) } returns Mono.just(foo) + every { mockResponse.bodyToMono(any>()) } returns Mono.just(foo) runBlocking { val responseEntity = WebClient.builder() .exchangeFunction(exchangeFunction)