Browse Source

Fix JdbcOperations Kotlin extensions

This commit updates JdbcOperationsExtensions.kt to:
 - Properly use the spread operator for invoking Java methods with
   a varargs parameter
 - Align JdbcOperationsExtensions return values nullability
   with the Java API (breaking change)
 - Use varargs where Java counterpart does (breaking change, undo some
   changes from gh-34668)
 - Use nullable args instead of non-nullable ones

 Closes gh-35846
pull/35860/head
Sébastien Deleuze 4 weeks ago
parent
commit
23f0cfb925
  1. 49
      spring-jdbc/src/main/kotlin/org/springframework/jdbc/core/JdbcOperationsExtensions.kt
  2. 73
      spring-jdbc/src/test/kotlin/org/springframework/jdbc/core/JdbcOperationsExtensionsTests.kt

49
spring-jdbc/src/main/kotlin/org/springframework/jdbc/core/JdbcOperationsExtensions.kt

@ -24,8 +24,8 @@ import java.sql.ResultSet @@ -24,8 +24,8 @@ import java.sql.ResultSet
* @author Mario Arias
* @since 5.0
*/
inline fun <reified T> JdbcOperations.queryForObject(sql: String): T =
queryForObject(sql, T::class.java as Class<*>) as T
inline fun <reified T : Any> JdbcOperations.queryForObject(sql: String): T? =
queryForObject(sql, T::class.java)
/**
* Extensions for [JdbcOperations.queryForObject] providing a RowMapper-like function
@ -34,7 +34,7 @@ inline fun <reified T> JdbcOperations.queryForObject(sql: String): T = @@ -34,7 +34,7 @@ inline fun <reified T> JdbcOperations.queryForObject(sql: String): T =
* @author Mario Arias
* @since 5.0
*/
inline fun <reified T> JdbcOperations.queryForObject(sql: String, vararg args: Any, crossinline function: (ResultSet, Int) -> T): T =
inline fun <reified T> JdbcOperations.queryForObject(sql: String, vararg args: Any?, crossinline function: (ResultSet, Int) -> T): T =
queryForObject(sql, { resultSet, i -> function(resultSet, i) }, *args)
/**
@ -44,18 +44,18 @@ inline fun <reified T> JdbcOperations.queryForObject(sql: String, vararg args: A @@ -44,18 +44,18 @@ inline fun <reified T> JdbcOperations.queryForObject(sql: String, vararg args: A
* @author Mario Arias
* @since 5.0
*/
inline fun <reified T> JdbcOperations.queryForObject(sql: String, args: Array<out Any>, argTypes: IntArray): T =
queryForObject(sql, args, argTypes, T::class.java as Class<*>) as T
inline fun <reified T : Any> JdbcOperations.queryForObject(sql: String, args: Array<out Any?>, argTypes: IntArray): T? =
queryForObject(sql, args, argTypes, T::class.java)
/**
* Extension for [JdbcOperations.queryForObject] providing a
* `queryForObject<Foo>("...", arrayOf(arg1, argN))` variant.
* `queryForObject<Foo>("...", arg1, argN)` variant.
*
* @author Mario Arias
* @since 5.0
* @author Sébastien Deleuze
* @since 7.0
*/
inline fun <reified T> JdbcOperations.queryForObject(sql: String, args: Array<out Any>): T =
queryForObject(sql, T::class.java as Class<*>, args) as T
inline fun <reified T : Any> JdbcOperations.queryForObject(sql: String, vararg args: Any?): T? =
queryForObject(sql, T::class.java, *args)
/**
* Extension for [JdbcOperations.queryForList] providing a `queryForList<Foo>("...")` variant.
@ -63,9 +63,8 @@ inline fun <reified T> JdbcOperations.queryForObject(sql: String, args: Array<ou @@ -63,9 +63,8 @@ inline fun <reified T> JdbcOperations.queryForObject(sql: String, args: Array<ou
* @author Mario Arias
* @since 5.0
*/
@Suppress("UNCHECKED_CAST")
inline fun <reified T> JdbcOperations.queryForList(sql: String): List<T> =
queryForList(sql, T::class.java) as List<T>
inline fun <reified T : Any> JdbcOperations.queryForList(sql: String): List<T?> =
queryForList(sql, T::class.java)
/**
* Extension for [JdbcOperations.queryForList] providing a
@ -74,21 +73,19 @@ inline fun <reified T> JdbcOperations.queryForList(sql: String): List<T> = @@ -74,21 +73,19 @@ inline fun <reified T> JdbcOperations.queryForList(sql: String): List<T> =
* @author Mario Arias
* @since 5.0
*/
@Suppress("UNCHECKED_CAST")
inline fun <reified T> JdbcOperations.queryForList(sql: String, args: Array<out Any>,
argTypes: IntArray): List<T> =
queryForList(sql, args, argTypes, T::class.java) as List<T>
inline fun <reified T : Any> JdbcOperations.queryForList(sql: String, args: Array<out Any?>,
argTypes: IntArray): List<T?> =
queryForList(sql, args, argTypes, T::class.java)
/**
* Extension for [JdbcOperations.queryForList] providing a
* `queryForList<Foo>("...", arrayOf(arg1, argN))` variant.
* `queryForList<Foo>("...", arg1, argN)` variant.
*
* @author Mario Arias
* @since 5.0
* @author Sebastien Deleuze
* @since 7.0
*/
@Suppress("UNCHECKED_CAST")
inline fun <reified T> JdbcOperations.queryForList(sql: String, args: Array<out Any>): List<T> =
queryForList(sql, T::class.java, args) as List<T>
inline fun <reified T : Any> JdbcOperations.queryForList(sql: String, vararg args: Any?): List<T?> =
queryForList(sql, T::class.java, *args)
/**
@ -98,7 +95,7 @@ inline fun <reified T> JdbcOperations.queryForList(sql: String, args: Array<out @@ -98,7 +95,7 @@ inline fun <reified T> JdbcOperations.queryForList(sql: String, args: Array<out
* @author Mario Arias
* @since 5.0
*/
fun <T> JdbcOperations.query(sql: String, vararg args: Any,
fun <T> JdbcOperations.query(sql: String, vararg args: Any?,
function: (ResultSet) -> T): T =
query(sql, ResultSetExtractor { function(it) }, *args)
@ -109,7 +106,7 @@ fun <T> JdbcOperations.query(sql: String, vararg args: Any, @@ -109,7 +106,7 @@ fun <T> JdbcOperations.query(sql: String, vararg args: Any,
* @author Mario Arias
* @since 5.0
*/
fun JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet) -> Unit): Unit =
fun JdbcOperations.query(sql: String, vararg args: Any?, function: (ResultSet) -> Unit): Unit =
query(sql, { function(it) }, *args)
/**
@ -119,5 +116,5 @@ fun JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet) -> @@ -119,5 +116,5 @@ fun JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet) ->
* @author Mario Arias
* @since 5.0
*/
fun <T> JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet, Int) -> T): List<T> =
fun <T> JdbcOperations.query(sql: String, vararg args: Any?, function: (ResultSet, Int) -> T): List<T> =
query(sql, { rs, i -> function(rs, i) }, *args)

73
spring-jdbc/src/test/kotlin/org/springframework/jdbc/core/JdbcOperationsExtensionsTests.kt

@ -46,7 +46,7 @@ class JdbcOperationsExtensionsTests { @@ -46,7 +46,7 @@ class JdbcOperationsExtensionsTests {
@Test
fun `queryForObject with nullable reified type parameters`() {
every { template.queryForObject(sql, any<Class<Int>>()) } returns null
assertThat(template.queryForObject<Int?>(sql)).isNull()
assertThat(template.queryForObject<Int>(sql)).isNull()
verify { template.queryForObject(sql, any<Class<Int>>()) }
}
@ -65,8 +65,17 @@ class JdbcOperationsExtensionsTests { @@ -65,8 +65,17 @@ class JdbcOperationsExtensionsTests {
}
@Test
fun `queryForObject with reified type parameters and argTypes`() {
val args = arrayOf(3)
fun `queryForObject with reified type parameters, non-null args array and argTypes`() {
val args = arrayOf(3, 4)
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
every { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) } returns 2
assertThat(template.queryForObject<Int>(sql, args, argTypes)).isEqualTo(2)
verify { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) }
}
@Test
fun `queryForObject with reified type parameters, nullable args array and argTypes`() {
val args = arrayOf(3, null)
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
every { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) } returns 2
assertThat(template.queryForObject<Int>(sql, args, argTypes)).isEqualTo(2)
@ -78,24 +87,22 @@ class JdbcOperationsExtensionsTests { @@ -78,24 +87,22 @@ class JdbcOperationsExtensionsTests {
val args = arrayOf(3)
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
every { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) } returns null
assertThat(template.queryForObject<Int?>(sql, args, argTypes)).isNull()
assertThat(template.queryForObject<Int>(sql, args, argTypes)).isNull()
verify { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) }
}
@Test
fun `queryForObject with reified type parameters and args`() {
val args = arrayOf(3, 4)
every { template.queryForObject(sql, any<Class<Int>>(), args) } returns 2
assertThat(template.queryForObject<Int>(sql, args)).isEqualTo(2)
verify { template.queryForObject(sql, any<Class<Int>>(), args) }
every { template.queryForObject(sql, any<Class<Int>>(), 3, null) } returns 2
assertThat(template.queryForObject<Int>(sql, 3, null)).isEqualTo(2)
verify { template.queryForObject(sql, any<Class<Int>>(), 3, null) }
}
@Test
fun `queryForObject with nullable reified type parameters and args`() {
val args = arrayOf(3, 4)
every { template.queryForObject(sql, any<Class<Int>>(), args) } returns null
assertThat(template.queryForObject<Int?>(sql, args)).isNull()
verify { template.queryForObject(sql, any<Class<Int>>(), args) }
every { template.queryForObject(sql, any<Class<Int>>(), 3, 4) } returns null
assertThat(template.queryForObject<Int>(sql, 3, 4)).isNull()
verify { template.queryForObject(sql, any<Class<Int>>(), 3, 4) }
}
@Test
@ -110,12 +117,12 @@ class JdbcOperationsExtensionsTests { @@ -110,12 +117,12 @@ class JdbcOperationsExtensionsTests {
fun `queryForList with nullable reified type parameters`() {
val list = listOf(1, null, 3)
every { template.queryForList(sql, any<Class<Int>>()) } returns list
assertThat(template.queryForList<Int?>(sql)).isEqualTo(list)
assertThat(template.queryForList<Int>(sql)).isEqualTo(list)
verify { template.queryForList(sql, any<Class<Int>>()) }
}
@Test
fun `queryForList with reified type parameters and argTypes`() {
fun `queryForList with reified type parameters, non-null args and argTypes`() {
val list = listOf(1, 2, 3)
val args = arrayOf(3)
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
@ -125,31 +132,49 @@ class JdbcOperationsExtensionsTests { @@ -125,31 +132,49 @@ class JdbcOperationsExtensionsTests {
}
@Test
fun `queryForList with nullable reified type parameters and argTypes`() {
fun `queryForList with reified type parameters, nullable args and argTypes`() {
val list = listOf(1, 2, 3)
val args = arrayOf("foo", null)
val argTypes = intArrayOf(JDBCType.VARCHAR.vendorTypeNumber)
every { template.queryForList(sql, args, argTypes, any<Class<Int>>()) } returns list
assertThat(template.queryForList<Int>(sql, args, argTypes)).isEqualTo(list)
verify { template.queryForList(sql, args, argTypes, any<Class<Int>>()) }
}
@Test
fun `queryForList with nullable reified type parameters, non-null args and argTypes`() {
val list = listOf(1, null, 3)
val args = arrayOf(3)
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
every { template.queryForList(sql, args, argTypes, any<Class<Int>>()) } returns list
assertThat(template.queryForList<Int?>(sql, args, argTypes)).isEqualTo(list)
assertThat(template.queryForList<Int>(sql, args, argTypes)).isEqualTo(list)
verify { template.queryForList(sql, args, argTypes, any<Class<Int>>()) }
}
@Test
fun `queryForList with nullable reified type parameters, nullable args and argTypes`() {
val list = listOf(1, null, 3)
val args = arrayOf("foo", null)
val argTypes = intArrayOf(JDBCType.VARCHAR.vendorTypeNumber)
every { template.queryForList(sql, args, argTypes, any<Class<Int>>()) } returns list
assertThat(template.queryForList<Int>(sql, args, argTypes)).isEqualTo(list)
verify { template.queryForList(sql, args, argTypes, any<Class<Int>>()) }
}
@Test
fun `queryForList with reified type parameters and args`() {
val list = listOf(1, 2, 3)
val args = arrayOf(3, 4)
every { template.queryForList(sql, any<Class<Int>>(), args) } returns list
template.queryForList<Int>(sql, args)
verify { template.queryForList(sql, any<Class<Int>>(), args) }
every { template.queryForList(sql, any<Class<Int>>(), 3, null) } returns list
template.queryForList<Int>(sql, 3, null)
verify { template.queryForList(sql, any<Class<Int>>(), 3, null) }
}
@Test
fun `queryForList with nullable reified type parameters and args`() {
val list = listOf(1, null, 3)
val args = arrayOf(3, 4)
every { template.queryForList(sql, any<Class<Int>>(), args) } returns list
template.queryForList<Int?>(sql, args)
verify { template.queryForList(sql, any<Class<Int>>(), args) }
every { template.queryForList(sql, any<Class<Int>>(), 3, null) } returns list
template.queryForList<Int>(sql, 3, null)
verify { template.queryForList(sql, any<Class<Int>>(), 3, null) }
}
@Test

Loading…
Cancel
Save