Skip to content

Commit 6583f9f

Browse files
committed
Use ParameterizedTypeReference instead of Class in Kotlin extensions
This commit also removes WebFlux non-extension functions in favor of regular Kotlin extensions leveraging ParameterizedTypeReference parameter. Issue: SPR-15818
1 parent 1d86c9c commit 6583f9f

File tree

16 files changed

+118
-211
lines changed

16 files changed

+118
-211
lines changed

spring-web/src/main/kotlin/org/springframework/web/client/RestOperationsExtensions.kt

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
package org.springframework.web.client
1818

19+
import org.springframework.core.ParameterizedTypeReference
1920
import org.springframework.http.HttpEntity
2021
import org.springframework.http.HttpMethod
2122
import org.springframework.http.RequestEntity
@@ -142,7 +143,7 @@ inline fun <reified T: Any> RestOperations.postForEntity(url: URI, request: Any)
142143
*/
143144
@Throws(RestClientException::class)
144145
inline fun <reified T: Any> RestOperations.exchange(url: String, method: HttpMethod, requestEntity: HttpEntity<*>, vararg uriVariables: Any): ResponseEntity<T> =
145-
exchange(url, method, requestEntity, T::class.java, *uriVariables)
146+
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, *uriVariables)
146147

147148
/**
148149
* Extension for [RestOperations.exchange] avoiding specifying the type parameter thanks to Kotlin reified type parameters.
@@ -153,7 +154,7 @@ inline fun <reified T: Any> RestOperations.exchange(url: String, method: HttpMet
153154
*/
154155
@Throws(RestClientException::class)
155156
inline fun <reified T: Any> RestOperations.exchange(url: String, method: HttpMethod, requestEntity: HttpEntity<*>, uriVariables: Map<String, *>): ResponseEntity<T> =
156-
exchange(url, method, requestEntity, T::class.java, uriVariables)
157+
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, uriVariables)
157158

158159
/**
159160
* Extension for [RestOperations.exchange] avoiding specifying the type parameter thanks to Kotlin reified type parameters.
@@ -164,7 +165,7 @@ inline fun <reified T: Any> RestOperations.exchange(url: String, method: HttpMet
164165
*/
165166
@Throws(RestClientException::class)
166167
inline fun <reified T: Any> RestOperations.exchange(url: URI, method: HttpMethod, requestEntity: HttpEntity<*>): ResponseEntity<T> =
167-
exchange(url, method, requestEntity, T::class.java)
168+
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {})
168169

169170
/**
170171
* Extension for [RestOperations.exchange] avoiding specifying the type parameter thanks to Kotlin reified type parameters.
@@ -175,4 +176,4 @@ inline fun <reified T: Any> RestOperations.exchange(url: URI, method: HttpMethod
175176
*/
176177
@Throws(RestClientException::class)
177178
inline fun <reified T: Any> RestOperations.exchange(requestEntity: RequestEntity<*>): ResponseEntity<T> =
178-
exchange(requestEntity, T::class.java)
179+
exchange(requestEntity, object : ParameterizedTypeReference<T>() {})

spring-web/src/test/kotlin/org/springframework/web/client/RestOperationsExtensionsTests.kt

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import org.mockito.Answers
2323
import org.mockito.Mock
2424
import org.mockito.Mockito.*
2525
import org.mockito.junit.MockitoJUnitRunner
26+
import org.springframework.core.ParameterizedTypeReference
2627
import org.springframework.http.HttpEntity
2728
import org.springframework.http.HttpMethod
2829
import org.springframework.http.RequestEntity
@@ -133,8 +134,8 @@ class RestOperationsExtensionsTests {
133134
val entity = mock<HttpEntity<Foo>>()
134135
val var1 = "var1"
135136
val var2 = "var2"
136-
template.exchange<Foo>(url, method, entity, var1, var2)
137-
verify(template, times(1)).exchange(url, method, entity, Foo::class.java, var1, var2)
137+
template.exchange<List<Foo>>(url, method, entity, var1, var2)
138+
verify(template, times(1)).exchange(url, method, entity, object : ParameterizedTypeReference<List<Foo>>() {}, var1, var2)
138139
}
139140

140141
@Test
@@ -143,24 +144,24 @@ class RestOperationsExtensionsTests {
143144
val method = HttpMethod.GET
144145
val entity = mock<HttpEntity<Foo>>()
145146
val vars = mapOf(Pair("key1", "value1"), Pair("key2", "value2"))
146-
template.exchange<Foo>(url, method, entity, vars)
147-
verify(template, times(1)).exchange(url, method, entity, Foo::class.java, vars)
147+
template.exchange<List<Foo>>(url, method, entity, vars)
148+
verify(template, times(1)).exchange(url, method, entity, object : ParameterizedTypeReference<List<Foo>>() {}, vars)
148149
}
149150

150151
@Test
151152
fun `exchange with reified type parameters, String, HttpMethod, HttpEntity`() {
152153
val url = "https://spring.io"
153154
val method = HttpMethod.GET
154155
val entity = mock<HttpEntity<Foo>>()
155-
template.exchange<Foo>(url, method, entity)
156-
verify(template, times(1)).exchange(url, method, entity, Foo::class.java)
156+
template.exchange<List<Foo>>(url, method, entity)
157+
verify(template, times(1)).exchange(url, method, entity, object : ParameterizedTypeReference<List<Foo>>() {})
157158
}
158159

159160
@Test
160161
fun `exchange with reified type parameters, String, HttpEntity`() {
161162
val entity = mock<RequestEntity<Foo>>()
162-
template.exchange<Foo>(entity)
163-
verify(template, times(1)).exchange(entity, Foo::class.java)
163+
template.exchange<List<Foo>>(entity)
164+
verify(template, times(1)).exchange(entity, object : ParameterizedTypeReference<List<Foo>>() {})
164165
}
165166

166167
class Foo

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/DefaultWebClient.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,12 @@ public RequestHeadersSpec<?> body(BodyInserter<?, ? super ClientHttpRequest> ins
294294
return this;
295295
}
296296

297+
@Override
298+
public <T, P extends Publisher<T>> RequestHeadersSpec<?> body(P publisher, ParameterizedTypeReference<T> typeReference) {
299+
this.inserter = BodyInserters.fromPublisher(publisher, typeReference);
300+
return this;
301+
}
302+
297303
@Override
298304
public <T, P extends Publisher<T>> RequestHeadersSpec<?> body(P publisher, Class<T> elementClass) {
299305
this.inserter = BodyInserters.fromPublisher(publisher, elementClass);

spring-webflux/src/main/java/org/springframework/web/reactive/function/client/WebClient.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,19 @@ interface RequestBodySpec extends RequestHeadersSpec<RequestBodySpec> {
518518
*/
519519
RequestHeadersSpec<?> body(BodyInserter<?, ? super ClientHttpRequest> inserter);
520520

521+
/**
522+
* Set the body of the request to the given asynchronous {@code Publisher}.
523+
* <p>This method is a convenient shortcut for {@link #body(BodyInserter)} with a
524+
* {@linkplain org.springframework.web.reactive.function.BodyInserters#fromPublisher}
525+
* Publisher body inserter}.
526+
* @param publisher the {@code Publisher} to write to the request
527+
* @param typeReference the type reference of elements contained in the publisher
528+
* @param <T> the type of the elements contained in the publisher
529+
* @param <P> the type of the {@code Publisher}
530+
* @return this builder
531+
*/
532+
<T, P extends Publisher<T>> RequestHeadersSpec<?> body(P publisher, ParameterizedTypeReference<T> typeReference);
533+
521534
/**
522535
* Set the body of the request to the given asynchronous {@code Publisher}.
523536
* <p>This method is a convenient shortcut for {@link #body(BodyInserter)} with a

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

Lines changed: 0 additions & 26 deletions
This file was deleted.

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

Lines changed: 0 additions & 39 deletions
This file was deleted.

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

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,39 +16,48 @@
1616

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

19+
import org.springframework.core.ParameterizedTypeReference
1920
import org.springframework.http.ResponseEntity
2021
import reactor.core.publisher.Flux
2122
import reactor.core.publisher.Mono
2223

2324

2425
/**
25-
* Extension for [ClientResponse.bodyToMono] providing a `bodyToMono<Foo>()` variant.
26+
* Extension for [ClientResponse.bodyToMono] providing a `bodyToMono<Foo>()` variant
27+
* leveraging Kotlin reified type parameters.
2628
*
2729
* @author Sebastien Deleuze
2830
* @since 5.0
2931
*/
30-
inline fun <reified T : Any> ClientResponse.bodyToMono(): Mono<T> = bodyToMono(T::class.java)
32+
inline fun <reified T : Any> ClientResponse.bodyToMono(): Mono<T> =
33+
bodyToMono(object : ParameterizedTypeReference<T>() {})
3134

3235
/**
33-
* Extension for [ClientResponse.bodyToFlux] providing a `bodyToFlux<Foo>()` variant.
36+
* Extension for [ClientResponse.bodyToFlux] providing a `bodyToFlux<Foo>()` variant
37+
* leveraging Kotlin reified type parameters.
3438
*
3539
* @author Sebastien Deleuze
3640
* @since 5.0
3741
*/
38-
inline fun <reified T : Any> ClientResponse.bodyToFlux(): Flux<T> = bodyToFlux(T::class.java)
42+
inline fun <reified T : Any> ClientResponse.bodyToFlux(): Flux<T> =
43+
bodyToFlux(object : ParameterizedTypeReference<T>() {})
3944

4045
/**
41-
* Extension for [ClientResponse.toEntity] providing a `toEntity<Foo>()` variant.
46+
* Extension for [ClientResponse.toEntity] providing a `toEntity<Foo>()` variant
47+
* leveraging Kotlin reified type parameters.
4248
*
4349
* @author Sebastien Deleuze
4450
* @since 5.0
4551
*/
46-
inline fun <reified T : Any> ClientResponse.toEntity(): Mono<ResponseEntity<T>> = toEntity(T::class.java)
52+
inline fun <reified T : Any> ClientResponse.toEntity(): Mono<ResponseEntity<T>> =
53+
toEntity(object : ParameterizedTypeReference<T>() {})
4754

4855
/**
49-
* Extension for [ClientResponse.toEntityList] providing a `bodyToEntityList<Foo>()` variant.
56+
* Extension for [ClientResponse.toEntityList] providing a `bodyToEntityList<Foo>()` variant
57+
* leveraging Kotlin reified type parameters.
5058
*
5159
* @author Sebastien Deleuze
5260
* @since 5.0
5361
*/
54-
inline fun <reified T : Any> ClientResponse.toEntityList(): Mono<ResponseEntity<List<T>>> = toEntityList(T::class.java)
62+
inline fun <reified T : Any> ClientResponse.toEntityList(): Mono<ResponseEntity<List<T>>> =
63+
toEntityList(object : ParameterizedTypeReference<T>() {})

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

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,39 @@
1717
package org.springframework.web.reactive.function.client
1818

1919
import org.reactivestreams.Publisher
20+
import org.springframework.core.ParameterizedTypeReference
2021
import reactor.core.publisher.Flux
2122
import reactor.core.publisher.Mono
2223

2324

2425
/**
25-
* Extension for [WebClient.RequestBodySpec.body] providing a variant without explicit class
26-
* parameter thanks to Kotlin reified type parameters.
26+
* Extension for [WebClient.RequestBodySpec.body] providing a `body<Foo>() variant
27+
* leveraging Kotlin reified type parameters.
2728
*
2829
* @author Sebastien Deleuze
2930
* @since 5.0
3031
*/
3132
@Suppress("EXTENSION_SHADOWED_BY_MEMBER")
32-
inline fun <reified T : Any, S : Publisher<T>> WebClient.RequestBodySpec.body(publisher: S): WebClient.RequestHeadersSpec<*>
33-
= body(publisher, T::class.java)
33+
inline fun <reified T : Any, S : Publisher<T>> WebClient.RequestBodySpec.body(publisher: S): WebClient.RequestHeadersSpec<*> =
34+
body(publisher, object : ParameterizedTypeReference<T>() {})
3435

3536
/**
36-
* Extension for [WebClient.ResponseSpec.bodyToMono] providing a `bodyToMono<Foo>()` variant.
37+
* Extension for [WebClient.ResponseSpec.bodyToMono] providing a `bodyToMono<Foo>()` variant
38+
* leveraging Kotlin reified type parameters.
3739
*
3840
* @author Sebastien Deleuze
3941
* @since 5.0
4042
*/
41-
inline fun <reified T : Any> WebClient.ResponseSpec.bodyToMono(): Mono<T> = bodyToMono(T::class.java)
43+
inline fun <reified T : Any> WebClient.ResponseSpec.bodyToMono(): Mono<T> =
44+
bodyToMono(object : ParameterizedTypeReference<T>() {})
4245

4346

4447
/**
45-
* Extension for [WebClient.ResponseSpec.bodyToFlux] providing a `bodyToFlux<Foo>()` variant.
48+
* Extension for [WebClient.ResponseSpec.bodyToFlux] providing a `bodyToFlux<Foo>()` variant
49+
* leveraging Kotlin reified type parameters.
4650
*
4751
* @author Sebastien Deleuze
4852
* @since 5.0
4953
*/
50-
inline fun <reified T : Any> WebClient.ResponseSpec.bodyToFlux(): Flux<T> = bodyToFlux(T::class.java)
54+
inline fun <reified T : Any> WebClient.ResponseSpec.bodyToFlux(): Flux<T> =
55+
bodyToFlux(object : ParameterizedTypeReference<T>() {})

spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerRequestExtensions.kt

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,27 @@
1616

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

19+
import org.springframework.core.ParameterizedTypeReference
1920
import reactor.core.publisher.Flux
2021
import reactor.core.publisher.Mono
2122

2223

2324
/**
24-
* Extension for [ServerRequest.bodyToMono] providing a `bodyToMono<Foo>()` variant.
25-
*
25+
* Extension for [ServerRequest.bodyToMono] providing a `bodyToMono<Foo>()` variant
26+
* leveraging Kotlin reified type parameters.
27+
*
2628
* @author Sebastien Deleuze
2729
* @since 5.0
2830
*/
29-
inline fun <reified T : Any> ServerRequest.bodyToMono(): Mono<T> = bodyToMono(T::class.java)
31+
inline fun <reified T : Any> ServerRequest.bodyToMono(): Mono<T> =
32+
bodyToMono(object : ParameterizedTypeReference<T>() {})
3033

3134
/**
32-
* Extension for [ServerRequest.bodyToFlux] providing a `bodyToFlux<Foo>()` variant.
35+
* Extension for [ServerRequest.bodyToFlux] providing a `bodyToFlux<Foo>()` variant
36+
* leveraging Kotlin reified type parameters.
3337
*
3438
* @author Sebastien Deleuze
3539
* @since 5.0
3640
*/
37-
inline fun <reified T : Any> ServerRequest.bodyToFlux(): Flux<T> = bodyToFlux(T::class.java)
41+
inline fun <reified T : Any> ServerRequest.bodyToFlux(): Flux<T> =
42+
bodyToFlux(object : ParameterizedTypeReference<T>() {})

spring-webflux/src/main/kotlin/org/springframework/web/reactive/function/server/ServerResponseExtensions.kt

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
package org.springframework.web.reactive.function.server
1818

1919
import org.reactivestreams.Publisher
20+
import org.springframework.core.ParameterizedTypeReference
21+
import org.springframework.http.MediaType
2022
import reactor.core.publisher.Mono
2123

2224
/**
@@ -25,4 +27,14 @@ import reactor.core.publisher.Mono
2527
* @author Sebastien Deleuze
2628
* @since 5.0
2729
*/
28-
inline fun <reified T : Any> ServerResponse.BodyBuilder.body(publisher: Publisher<T>): Mono<ServerResponse> = body(publisher, T::class.java)
30+
inline fun <reified T : Any> ServerResponse.BodyBuilder.body(publisher: Publisher<T>): Mono<ServerResponse> =
31+
body(publisher, object : ParameterizedTypeReference<T>() {})
32+
33+
/**
34+
* Extension for [ServerResponse.BodyBuilder.body] providing a `bodyToServerSentEvents(Publisher<T>)` variant.
35+
*
36+
* @author Sebastien Deleuze
37+
* @since 5.0
38+
*/
39+
inline fun <reified T : Any> ServerResponse.BodyBuilder.bodyToServerSentEvents(publisher: Publisher<T>): Mono<ServerResponse> =
40+
contentType(MediaType.TEXT_EVENT_STREAM).body(publisher, object : ParameterizedTypeReference<T>() {})

spring-webflux/src/test/kotlin/org/springframework/web/reactive/function/BodyExtractorsExtensionsTests.kt

Lines changed: 0 additions & 44 deletions
This file was deleted.

0 commit comments

Comments
 (0)