Skip to content

Commit d4c91d2

Browse files
sdeleuzesnicoll
authored andcommitted
Improve Kotlin extensions doc about type erasure
Since type erasure can be fixed only when using ParameterizedTypeReference based Java methods, TestRestTemplate API documentation should be updated to specify which extensions are subject to type erasure, and which are not. Closes gh-11604
1 parent b7a9933 commit d4c91d2

File tree

2 files changed

+123
-50
lines changed

2 files changed

+123
-50
lines changed

spring-boot-project/spring-boot-test/src/main/kotlin/org/springframework/boot/test/web/client/TestRestTemplateExtensions.kt

+93-50
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,10 @@ import org.springframework.web.client.RestClientException
2525
import java.net.URI
2626

2727
/**
28-
* Extension for [TestRestTemplate.getForObject] avoiding specifying the type
29-
* parameter thanks to Kotlin reified type parameters.
28+
* Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`
29+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
30+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
31+
* generic type arguments.
3032
*
3133
* @author Sebastien Deleuze
3234
* @since 2.0.0
@@ -36,8 +38,10 @@ inline fun <reified T : Any> TestRestTemplate.getForObject(url: String, vararg u
3638
getForObject(url, T::class.java, *uriVariables)
3739

3840
/**
39-
* Extension for [TestRestTemplate.getForObject] avoiding specifying the type
40-
* parameter thanks to Kotlin reified type parameters.
41+
* Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`
42+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
43+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
44+
* generic type arguments.
4145
*
4246
* @author Sebastien Deleuze
4347
* @since 2.0.0
@@ -47,8 +51,10 @@ inline fun <reified T : Any> TestRestTemplate.getForObject(url: String, uriVaria
4751
getForObject(url, T::class.java, uriVariables)
4852

4953
/**
50-
* Extension for [TestRestTemplate.getForObject] avoiding specifying the type parameter
51-
* thanks to Kotlin reified type parameters.
54+
* Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`
55+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
56+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
57+
* generic type arguments.
5258
*
5359
* @author Sebastien Deleuze
5460
* @since 2.0.0
@@ -58,8 +64,10 @@ inline fun <reified T : Any> TestRestTemplate.getForObject(url: URI): T? =
5864
getForObject(url, T::class.java)
5965

6066
/**
61-
* Extension for [TestRestTemplate.getForEntity] avoiding requiring the type parameter
62-
* thanks to Kotlin reified type parameters.
67+
* Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`
68+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
69+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
70+
* generic type arguments.
6371
*
6472
* @author Sebastien Deleuze
6573
* @since 2.0.0
@@ -69,8 +77,10 @@ inline fun <reified T : Any> TestRestTemplate.getForEntity(url: URI): ResponseEn
6977
getForEntity(url, T::class.java)
7078

7179
/**
72-
* Extension for [TestRestTemplate.getForEntity] avoiding requiring the type parameter
73-
* thanks to Kotlin reified type parameters.
80+
* Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`
81+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
82+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
83+
* generic type arguments.
7484
*
7585
* @author Sebastien Deleuze
7686
* @since 2.0.0
@@ -80,8 +90,10 @@ inline fun <reified T : Any> TestRestTemplate.getForEntity(url: String, vararg u
8090
getForEntity(url, T::class.java, *uriVariables)
8191

8292
/**
83-
* Extension for [TestRestTemplate.getForEntity] avoiding requiring the type parameter
84-
* thanks to Kotlin reified type parameters.
93+
* Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`
94+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
95+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
96+
* generic type arguments.
8597
*
8698
* @author Sebastien Deleuze
8799
* @since 2.0.0
@@ -91,140 +103,171 @@ inline fun <reified T : Any> TestRestTemplate.getForEntity(url: String, uriVaria
91103
getForEntity(url, T::class.java, uriVariables)
92104

93105
/**
94-
* Extension for [TestRestTemplate.patchForObject] avoiding specifying the type parameter
95-
* thanks to Kotlin reified type parameters.
106+
* Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`
107+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
108+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
109+
* generic type arguments.
96110
*
97111
* @author Sebastien Deleuze
98112
* @since 2.0.0
99113
*/
100114
@Throws(RestClientException::class)
101-
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any, vararg uriVariables: Any): T? =
115+
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any? = null,
116+
vararg uriVariables: Any): T? =
102117
patchForObject(url, request, T::class.java, *uriVariables)
103118

104119
/**
105-
* Extension for [TestRestTemplate.patchForObject] avoiding specifying the type parameter
106-
* thanks to Kotlin reified type parameters.
120+
* Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`
121+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
122+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
123+
* generic type arguments.
107124
*
108125
* @author Sebastien Deleuze
109126
* @since 2.0.0
110127
*/
111128
@Throws(RestClientException::class)
112-
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any, uriVariables: Map<String, *>): T? =
129+
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any? = null,
130+
uriVariables: Map<String, *>): T? =
113131
patchForObject(url, request, T::class.java, uriVariables)
114132

115133
/**
116-
* Extension for [TestRestTemplate.patchForObject] avoiding specifying the type parameter
117-
* thanks to Kotlin reified type parameters.
134+
* Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`
135+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
136+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
137+
* generic type arguments.
118138
*
119139
* @author Sebastien Deleuze
120140
* @since 2.0.0
121141
*/
122142
@Throws(RestClientException::class)
123-
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: URI, request: Any): T? =
143+
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: URI, request: Any? = null): T? =
124144
patchForObject(url, request, T::class.java)
125145

126146
/**
127-
* Extension for [TestRestTemplate.postForObject] avoiding specifying the type parameter
128-
* thanks to Kotlin reified type parameters.
147+
* Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`
148+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
149+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
150+
* generic type arguments.
129151
*
130152
* @author Sebastien Deleuze
131153
* @since 2.0.0
132154
*/
133155
@Throws(RestClientException::class)
134-
inline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any, vararg uriVariables: Any): T? =
156+
inline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any? = null,
157+
vararg uriVariables: Any): T? =
135158
postForObject(url, request, T::class.java, *uriVariables)
136159

137160
/**
138-
* Extension for [TestRestTemplate.postForObject] avoiding specifying the type parameter
139-
* thanks to Kotlin reified type parameters.
161+
* Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`
162+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
163+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
164+
* generic type arguments.
140165
*
141166
* @author Sebastien Deleuze
142167
* @since 2.0.0
143168
*/
144169
@Throws(RestClientException::class)
145-
inline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any, uriVariables: Map<String, *>): T? =
170+
inline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any? = null,
171+
uriVariables: Map<String, *>): T? =
146172
postForObject(url, request, T::class.java, uriVariables)
147173

148174
/**
149-
* Extension for [TestRestTemplate.postForObject] avoiding specifying the type parameter
150-
* thanks to Kotlin reified type parameters.
175+
* Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`
176+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
177+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
178+
* generic type arguments.
151179
*
152180
* @author Sebastien Deleuze
153181
* @since 2.0.0
154182
*/
155183
@Throws(RestClientException::class)
156-
inline fun <reified T : Any> TestRestTemplate.postForObject(url: URI, request: Any): T? =
184+
inline fun <reified T : Any> TestRestTemplate.postForObject(url: URI, request: Any? = null): T? =
157185
postForObject(url, request, T::class.java)
158186

159187
/**
160-
* Extension for [TestRestTemplate.postForEntity] avoiding specifying the type parameter
161-
* thanks to Kotlin reified type parameters.
188+
* Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`
189+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
190+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
191+
* generic type arguments.
162192
*
163193
* @author Sebastien Deleuze
164194
* @since 2.0.0
165195
*/
166196
@Throws(RestClientException::class)
167-
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any, vararg uriVariables: Any): ResponseEntity<T> =
197+
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any? = null,
198+
vararg uriVariables: Any): ResponseEntity<T> =
168199
postForEntity(url, request, T::class.java, *uriVariables)
169200

170201
/**
171-
* Extension for [TestRestTemplate.postForEntity] avoiding specifying the type parameter
172-
* thanks to Kotlin reified type parameters.
202+
* Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`
203+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
204+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
205+
* generic type arguments.
173206
*
174207
* @author Sebastien Deleuze
175208
* @since 2.0.0
176209
*/
177210
@Throws(RestClientException::class)
178-
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any, uriVariables: Map<String, *>): ResponseEntity<T> =
211+
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any? = null,
212+
uriVariables: Map<String, *>): ResponseEntity<T> =
179213
postForEntity(url, request, T::class.java, uriVariables)
180214

181215
/**
182-
* Extension for [TestRestTemplate.postForEntity] avoiding specifying the type parameter
183-
* thanks to Kotlin reified type parameters.
216+
* Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`
217+
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
218+
* extension is subject to type erasure. Use [exchange] if you need to retain actual
219+
* generic type arguments.
184220
*
185221
* @author Sebastien Deleuze
186222
* @since 2.0.0
187223
*/
188224
@Throws(RestClientException::class)
189-
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: URI, request: Any): ResponseEntity<T> =
225+
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: URI, request: Any? = null): ResponseEntity<T> =
190226
postForEntity(url, request, T::class.java)
191227

192228
/**
193-
* Extension for [TestRestTemplate.exchange] avoiding specifying the type parameter
194-
* thanks to Kotlin reified type parameters.
229+
* Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`
230+
* variant leveraging Kotlin reified type parameters. This extension is not subject to
231+
* type erasure and retains actual generic type arguments.
195232
*
196233
* @author Sebastien Deleuze
197234
* @since 2.0.0
198235
*/
199236
@Throws(RestClientException::class)
200-
inline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod, requestEntity: HttpEntity<*>, vararg uriVariables: Any): ResponseEntity<T> =
237+
inline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod,
238+
requestEntity: HttpEntity<*>? = null, vararg uriVariables: Any): ResponseEntity<T> =
201239
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, *uriVariables)
202240

203241
/**
204-
* Extension for [TestRestTemplate.exchange] avoiding specifying the type parameter
205-
* thanks to Kotlin reified type parameters.
242+
* Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`
243+
* variant leveraging Kotlin reified type parameters. This extension is not subject to
244+
* type erasure and retains actual generic type arguments.
206245
*
207246
* @author Sebastien Deleuze
208247
* @since 2.0.0
209248
*/
210249
@Throws(RestClientException::class)
211-
inline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod, requestEntity: HttpEntity<*>, uriVariables: Map<String, *>): ResponseEntity<T> =
250+
inline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod,
251+
requestEntity: HttpEntity<*>? = null, uriVariables: Map<String, *>): ResponseEntity<T> =
212252
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, uriVariables)
213253

214254
/**
215-
* Extension for [TestRestTemplate.exchange] avoiding specifying the type parameter
216-
* thanks to Kotlin reified type parameters.
255+
* Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`
256+
* variant leveraging Kotlin reified type parameters. This extension is not subject to
257+
* type erasure and retains actual generic type arguments.
217258
*
218259
* @author Sebastien Deleuze
219260
* @since 2.0.0
220261
*/
221262
@Throws(RestClientException::class)
222-
inline fun <reified T : Any> TestRestTemplate.exchange(url: URI, method: HttpMethod, requestEntity: HttpEntity<*>): ResponseEntity<T> =
263+
inline fun <reified T : Any> TestRestTemplate.exchange(url: URI, method: HttpMethod,
264+
requestEntity: HttpEntity<*>? = null): ResponseEntity<T> =
223265
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {})
224266

225267
/**
226-
* Extension for [TestRestTemplate.exchange] avoiding specifying the type parameter
227-
* thanks to Kotlin reified type parameters.
268+
* Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`
269+
* variant leveraging Kotlin reified type parameters. This extension is not subject to
270+
* type erasure and retains actual generic type arguments.
228271
*
229272
* @author Sebastien Deleuze
230273
* @since 2.0.0

spring-boot-project/spring-boot-test/src/test/kotlin/org/springframework/boot/test/web/client/TestRestTemplateExtensionsTests.kt

+30
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,13 @@ class TestRestTemplateExtensionsTests {
122122
verify(template, times(1)).patchForObject(url, body, Foo::class.java)
123123
}
124124

125+
@Test
126+
fun `patchForObject with reified type parameters`() {
127+
val url = "https://spring.io"
128+
template.patchForObject<Foo>(url)
129+
verify(template, times(1)).patchForObject(url, null, Foo::class.java)
130+
}
131+
125132
@Test
126133
fun `postForObject with reified type parameters, String, Any and varargs`() {
127134
val url = "https://spring.io"
@@ -149,6 +156,13 @@ class TestRestTemplateExtensionsTests {
149156
verify(template, times(1)).postForObject(url, body, Foo::class.java)
150157
}
151158

159+
@Test
160+
fun `postForObject with reified type parameters`() {
161+
val url = "https://spring.io"
162+
template.postForObject<Foo>(url)
163+
verify(template, times(1)).postForObject(url, null, Foo::class.java)
164+
}
165+
152166
@Test
153167
fun `postForEntity with reified type parameters, String, Any and varargs`() {
154168
val url = "https://spring.io"
@@ -176,6 +190,13 @@ class TestRestTemplateExtensionsTests {
176190
verify(template, times(1)).postForEntity(url, body, Foo::class.java)
177191
}
178192

193+
@Test
194+
fun `postForEntity with reified type parameters`() {
195+
val url = "https://spring.io"
196+
template.postForEntity<Foo>(url)
197+
verify(template, times(1)).postForEntity(url, null, Foo::class.java)
198+
}
199+
179200
@Test
180201
fun `exchange with reified type parameters, String, HttpMethod, HttpEntity and varargs`() {
181202
val url = "https://spring.io"
@@ -217,6 +238,15 @@ class TestRestTemplateExtensionsTests {
217238
object : ParameterizedTypeReference<List<Foo>>() {})
218239
}
219240

241+
@Test
242+
fun `exchange with reified type parameters, String and HttpMethod`() {
243+
val url = "https://spring.io"
244+
val method = HttpMethod.GET
245+
template.exchange<List<Foo>>(url, method)
246+
verify(template, times(1)).exchange(url, method, null,
247+
object : ParameterizedTypeReference<List<Foo>>() {})
248+
}
249+
220250
@Test
221251
fun `RestOperations are available`() {
222252
val extensions = Class.forName(

0 commit comments

Comments
 (0)