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
This commit is contained in:
sdeleuze 2018-01-11 15:39:32 +01:00 committed by Stephane Nicoll
parent b7a993358d
commit d4c91d2fe0
2 changed files with 123 additions and 50 deletions

View File

@ -25,8 +25,10 @@ import org.springframework.web.client.RestClientException
import java.net.URI
/**
* Extension for [TestRestTemplate.getForObject] avoiding specifying the type
* parameter thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
@ -36,8 +38,10 @@ inline fun <reified T : Any> TestRestTemplate.getForObject(url: String, vararg u
getForObject(url, T::class.java, *uriVariables)
/**
* Extension for [TestRestTemplate.getForObject] avoiding specifying the type
* parameter thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
@ -47,8 +51,10 @@ inline fun <reified T : Any> TestRestTemplate.getForObject(url: String, uriVaria
getForObject(url, T::class.java, uriVariables)
/**
* Extension for [TestRestTemplate.getForObject] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.getForObject] providing a `getForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
@ -58,8 +64,10 @@ inline fun <reified T : Any> TestRestTemplate.getForObject(url: URI): T? =
getForObject(url, T::class.java)
/**
* Extension for [TestRestTemplate.getForEntity] avoiding requiring the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
@ -69,8 +77,10 @@ inline fun <reified T : Any> TestRestTemplate.getForEntity(url: URI): ResponseEn
getForEntity(url, T::class.java)
/**
* Extension for [TestRestTemplate.getForEntity] avoiding requiring the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
@ -80,8 +90,10 @@ inline fun <reified T : Any> TestRestTemplate.getForEntity(url: String, vararg u
getForEntity(url, T::class.java, *uriVariables)
/**
* Extension for [TestRestTemplate.getForEntity] avoiding requiring the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.getForEntity] providing a `getForEntity<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
@ -91,140 +103,171 @@ inline fun <reified T : Any> TestRestTemplate.getForEntity(url: String, uriVaria
getForEntity(url, T::class.java, uriVariables)
/**
* Extension for [TestRestTemplate.patchForObject] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any, vararg uriVariables: Any): T? =
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any? = null,
vararg uriVariables: Any): T? =
patchForObject(url, request, T::class.java, *uriVariables)
/**
* Extension for [TestRestTemplate.patchForObject] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any, uriVariables: Map<String, *>): T? =
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: String, request: Any? = null,
uriVariables: Map<String, *>): T? =
patchForObject(url, request, T::class.java, uriVariables)
/**
* Extension for [TestRestTemplate.patchForObject] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.patchForObject] providing a `patchForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: URI, request: Any): T? =
inline fun <reified T : Any> TestRestTemplate.patchForObject(url: URI, request: Any? = null): T? =
patchForObject(url, request, T::class.java)
/**
* Extension for [TestRestTemplate.postForObject] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any, vararg uriVariables: Any): T? =
inline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any? = null,
vararg uriVariables: Any): T? =
postForObject(url, request, T::class.java, *uriVariables)
/**
* Extension for [TestRestTemplate.postForObject] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any, uriVariables: Map<String, *>): T? =
inline fun <reified T : Any> TestRestTemplate.postForObject(url: String, request: Any? = null,
uriVariables: Map<String, *>): T? =
postForObject(url, request, T::class.java, uriVariables)
/**
* Extension for [TestRestTemplate.postForObject] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.postForObject] providing a `postForObject<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.postForObject(url: URI, request: Any): T? =
inline fun <reified T : Any> TestRestTemplate.postForObject(url: URI, request: Any? = null): T? =
postForObject(url, request, T::class.java)
/**
* Extension for [TestRestTemplate.postForEntity] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any, vararg uriVariables: Any): ResponseEntity<T> =
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any? = null,
vararg uriVariables: Any): ResponseEntity<T> =
postForEntity(url, request, T::class.java, *uriVariables)
/**
* Extension for [TestRestTemplate.postForEntity] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any, uriVariables: Map<String, *>): ResponseEntity<T> =
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: String, request: Any? = null,
uriVariables: Map<String, *>): ResponseEntity<T> =
postForEntity(url, request, T::class.java, uriVariables)
/**
* Extension for [TestRestTemplate.postForEntity] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.postForEntity] providing a `postForEntity<Foo>(...)`
* variant leveraging Kotlin reified type parameters. Like the original Java method, this
* extension is subject to type erasure. Use [exchange] if you need to retain actual
* generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: URI, request: Any): ResponseEntity<T> =
inline fun <reified T : Any> TestRestTemplate.postForEntity(url: URI, request: Any? = null): ResponseEntity<T> =
postForEntity(url, request, T::class.java)
/**
* Extension for [TestRestTemplate.exchange] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`
* variant leveraging Kotlin reified type parameters. This extension is not subject to
* type erasure and retains actual generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod, requestEntity: HttpEntity<*>, vararg uriVariables: Any): ResponseEntity<T> =
inline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod,
requestEntity: HttpEntity<*>? = null, vararg uriVariables: Any): ResponseEntity<T> =
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, *uriVariables)
/**
* Extension for [TestRestTemplate.exchange] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`
* variant leveraging Kotlin reified type parameters. This extension is not subject to
* type erasure and retains actual generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod, requestEntity: HttpEntity<*>, uriVariables: Map<String, *>): ResponseEntity<T> =
inline fun <reified T : Any> TestRestTemplate.exchange(url: String, method: HttpMethod,
requestEntity: HttpEntity<*>? = null, uriVariables: Map<String, *>): ResponseEntity<T> =
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {}, uriVariables)
/**
* Extension for [TestRestTemplate.exchange] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`
* variant leveraging Kotlin reified type parameters. This extension is not subject to
* type erasure and retains actual generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0
*/
@Throws(RestClientException::class)
inline fun <reified T : Any> TestRestTemplate.exchange(url: URI, method: HttpMethod, requestEntity: HttpEntity<*>): ResponseEntity<T> =
inline fun <reified T : Any> TestRestTemplate.exchange(url: URI, method: HttpMethod,
requestEntity: HttpEntity<*>? = null): ResponseEntity<T> =
exchange(url, method, requestEntity, object : ParameterizedTypeReference<T>() {})
/**
* Extension for [TestRestTemplate.exchange] avoiding specifying the type parameter
* thanks to Kotlin reified type parameters.
* Extension for [TestRestTemplate.exchange] providing an `exchange<Foo>(...)`
* variant leveraging Kotlin reified type parameters. This extension is not subject to
* type erasure and retains actual generic type arguments.
*
* @author Sebastien Deleuze
* @since 2.0.0

View File

@ -122,6 +122,13 @@ class TestRestTemplateExtensionsTests {
verify(template, times(1)).patchForObject(url, body, Foo::class.java)
}
@Test
fun `patchForObject with reified type parameters`() {
val url = "https://spring.io"
template.patchForObject<Foo>(url)
verify(template, times(1)).patchForObject(url, null, Foo::class.java)
}
@Test
fun `postForObject with reified type parameters, String, Any and varargs`() {
val url = "https://spring.io"
@ -149,6 +156,13 @@ class TestRestTemplateExtensionsTests {
verify(template, times(1)).postForObject(url, body, Foo::class.java)
}
@Test
fun `postForObject with reified type parameters`() {
val url = "https://spring.io"
template.postForObject<Foo>(url)
verify(template, times(1)).postForObject(url, null, Foo::class.java)
}
@Test
fun `postForEntity with reified type parameters, String, Any and varargs`() {
val url = "https://spring.io"
@ -176,6 +190,13 @@ class TestRestTemplateExtensionsTests {
verify(template, times(1)).postForEntity(url, body, Foo::class.java)
}
@Test
fun `postForEntity with reified type parameters`() {
val url = "https://spring.io"
template.postForEntity<Foo>(url)
verify(template, times(1)).postForEntity(url, null, Foo::class.java)
}
@Test
fun `exchange with reified type parameters, String, HttpMethod, HttpEntity and varargs`() {
val url = "https://spring.io"
@ -217,6 +238,15 @@ class TestRestTemplateExtensionsTests {
object : ParameterizedTypeReference<List<Foo>>() {})
}
@Test
fun `exchange with reified type parameters, String and HttpMethod`() {
val url = "https://spring.io"
val method = HttpMethod.GET
template.exchange<List<Foo>>(url, method)
verify(template, times(1)).exchange(url, method, null,
object : ParameterizedTypeReference<List<Foo>>() {})
}
@Test
fun `RestOperations are available`() {
val extensions = Class.forName(