Skip to content

Commit 23f0cfb

Browse files
committed
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
1 parent 2cca560 commit 23f0cfb

File tree

2 files changed

+72
-50
lines changed

2 files changed

+72
-50
lines changed

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

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,8 @@ import java.sql.ResultSet
2424
* @author Mario Arias
2525
* @since 5.0
2626
*/
27-
inline fun <reified T> JdbcOperations.queryForObject(sql: String): T =
28-
queryForObject(sql, T::class.java as Class<*>) as T
27+
inline fun <reified T : Any> JdbcOperations.queryForObject(sql: String): T? =
28+
queryForObject(sql, T::class.java)
2929

3030
/**
3131
* Extensions for [JdbcOperations.queryForObject] providing a RowMapper-like function
@@ -34,7 +34,7 @@ inline fun <reified T> JdbcOperations.queryForObject(sql: String): T =
3434
* @author Mario Arias
3535
* @since 5.0
3636
*/
37-
inline fun <reified T> JdbcOperations.queryForObject(sql: String, vararg args: Any, crossinline function: (ResultSet, Int) -> T): T =
37+
inline fun <reified T> JdbcOperations.queryForObject(sql: String, vararg args: Any?, crossinline function: (ResultSet, Int) -> T): T =
3838
queryForObject(sql, { resultSet, i -> function(resultSet, i) }, *args)
3939

4040
/**
@@ -44,28 +44,27 @@ inline fun <reified T> JdbcOperations.queryForObject(sql: String, vararg args: A
4444
* @author Mario Arias
4545
* @since 5.0
4646
*/
47-
inline fun <reified T> JdbcOperations.queryForObject(sql: String, args: Array<out Any>, argTypes: IntArray): T =
48-
queryForObject(sql, args, argTypes, T::class.java as Class<*>) as T
47+
inline fun <reified T : Any> JdbcOperations.queryForObject(sql: String, args: Array<out Any?>, argTypes: IntArray): T? =
48+
queryForObject(sql, args, argTypes, T::class.java)
4949

5050
/**
5151
* Extension for [JdbcOperations.queryForObject] providing a
52-
* `queryForObject<Foo>("...", arrayOf(arg1, argN))` variant.
52+
* `queryForObject<Foo>("...", arg1, argN)` variant.
5353
*
54-
* @author Mario Arias
55-
* @since 5.0
54+
* @author Sébastien Deleuze
55+
* @since 7.0
5656
*/
57-
inline fun <reified T> JdbcOperations.queryForObject(sql: String, args: Array<out Any>): T =
58-
queryForObject(sql, T::class.java as Class<*>, args) as T
57+
inline fun <reified T : Any> JdbcOperations.queryForObject(sql: String, vararg args: Any?): T? =
58+
queryForObject(sql, T::class.java, *args)
5959

6060
/**
6161
* Extension for [JdbcOperations.queryForList] providing a `queryForList<Foo>("...")` variant.
6262
*
6363
* @author Mario Arias
6464
* @since 5.0
6565
*/
66-
@Suppress("UNCHECKED_CAST")
67-
inline fun <reified T> JdbcOperations.queryForList(sql: String): List<T> =
68-
queryForList(sql, T::class.java) as List<T>
66+
inline fun <reified T : Any> JdbcOperations.queryForList(sql: String): List<T?> =
67+
queryForList(sql, T::class.java)
6968

7069
/**
7170
* Extension for [JdbcOperations.queryForList] providing a
@@ -74,21 +73,19 @@ inline fun <reified T> JdbcOperations.queryForList(sql: String): List<T> =
7473
* @author Mario Arias
7574
* @since 5.0
7675
*/
77-
@Suppress("UNCHECKED_CAST")
78-
inline fun <reified T> JdbcOperations.queryForList(sql: String, args: Array<out Any>,
79-
argTypes: IntArray): List<T> =
80-
queryForList(sql, args, argTypes, T::class.java) as List<T>
76+
inline fun <reified T : Any> JdbcOperations.queryForList(sql: String, args: Array<out Any?>,
77+
argTypes: IntArray): List<T?> =
78+
queryForList(sql, args, argTypes, T::class.java)
8179

8280
/**
8381
* Extension for [JdbcOperations.queryForList] providing a
84-
* `queryForList<Foo>("...", arrayOf(arg1, argN))` variant.
82+
* `queryForList<Foo>("...", arg1, argN)` variant.
8583
*
86-
* @author Mario Arias
87-
* @since 5.0
84+
* @author Sebastien Deleuze
85+
* @since 7.0
8886
*/
89-
@Suppress("UNCHECKED_CAST")
90-
inline fun <reified T> JdbcOperations.queryForList(sql: String, args: Array<out Any>): List<T> =
91-
queryForList(sql, T::class.java, args) as List<T>
87+
inline fun <reified T : Any> JdbcOperations.queryForList(sql: String, vararg args: Any?): List<T?> =
88+
queryForList(sql, T::class.java, *args)
9289

9390

9491
/**
@@ -98,7 +95,7 @@ inline fun <reified T> JdbcOperations.queryForList(sql: String, args: Array<out
9895
* @author Mario Arias
9996
* @since 5.0
10097
*/
101-
fun <T> JdbcOperations.query(sql: String, vararg args: Any,
98+
fun <T> JdbcOperations.query(sql: String, vararg args: Any?,
10299
function: (ResultSet) -> T): T =
103100
query(sql, ResultSetExtractor { function(it) }, *args)
104101

@@ -109,7 +106,7 @@ fun <T> JdbcOperations.query(sql: String, vararg args: Any,
109106
* @author Mario Arias
110107
* @since 5.0
111108
*/
112-
fun JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet) -> Unit): Unit =
109+
fun JdbcOperations.query(sql: String, vararg args: Any?, function: (ResultSet) -> Unit): Unit =
113110
query(sql, { function(it) }, *args)
114111

115112
/**
@@ -119,5 +116,5 @@ fun JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet) ->
119116
* @author Mario Arias
120117
* @since 5.0
121118
*/
122-
fun <T> JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet, Int) -> T): List<T> =
119+
fun <T> JdbcOperations.query(sql: String, vararg args: Any?, function: (ResultSet, Int) -> T): List<T> =
123120
query(sql, { rs, i -> function(rs, i) }, *args)

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

Lines changed: 49 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ class JdbcOperationsExtensionsTests {
4646
@Test
4747
fun `queryForObject with nullable reified type parameters`() {
4848
every { template.queryForObject(sql, any<Class<Int>>()) } returns null
49-
assertThat(template.queryForObject<Int?>(sql)).isNull()
49+
assertThat(template.queryForObject<Int>(sql)).isNull()
5050
verify { template.queryForObject(sql, any<Class<Int>>()) }
5151
}
5252

@@ -65,8 +65,17 @@ class JdbcOperationsExtensionsTests {
6565
}
6666

6767
@Test
68-
fun `queryForObject with reified type parameters and argTypes`() {
69-
val args = arrayOf(3)
68+
fun `queryForObject with reified type parameters, non-null args array and argTypes`() {
69+
val args = arrayOf(3, 4)
70+
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
71+
every { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) } returns 2
72+
assertThat(template.queryForObject<Int>(sql, args, argTypes)).isEqualTo(2)
73+
verify { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) }
74+
}
75+
76+
@Test
77+
fun `queryForObject with reified type parameters, nullable args array and argTypes`() {
78+
val args = arrayOf(3, null)
7079
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
7180
every { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) } returns 2
7281
assertThat(template.queryForObject<Int>(sql, args, argTypes)).isEqualTo(2)
@@ -78,24 +87,22 @@ class JdbcOperationsExtensionsTests {
7887
val args = arrayOf(3)
7988
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
8089
every { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) } returns null
81-
assertThat(template.queryForObject<Int?>(sql, args, argTypes)).isNull()
90+
assertThat(template.queryForObject<Int>(sql, args, argTypes)).isNull()
8291
verify { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) }
8392
}
8493

8594
@Test
8695
fun `queryForObject with reified type parameters and args`() {
87-
val args = arrayOf(3, 4)
88-
every { template.queryForObject(sql, any<Class<Int>>(), args) } returns 2
89-
assertThat(template.queryForObject<Int>(sql, args)).isEqualTo(2)
90-
verify { template.queryForObject(sql, any<Class<Int>>(), args) }
96+
every { template.queryForObject(sql, any<Class<Int>>(), 3, null) } returns 2
97+
assertThat(template.queryForObject<Int>(sql, 3, null)).isEqualTo(2)
98+
verify { template.queryForObject(sql, any<Class<Int>>(), 3, null) }
9199
}
92100

93101
@Test
94102
fun `queryForObject with nullable reified type parameters and args`() {
95-
val args = arrayOf(3, 4)
96-
every { template.queryForObject(sql, any<Class<Int>>(), args) } returns null
97-
assertThat(template.queryForObject<Int?>(sql, args)).isNull()
98-
verify { template.queryForObject(sql, any<Class<Int>>(), args) }
103+
every { template.queryForObject(sql, any<Class<Int>>(), 3, 4) } returns null
104+
assertThat(template.queryForObject<Int>(sql, 3, 4)).isNull()
105+
verify { template.queryForObject(sql, any<Class<Int>>(), 3, 4) }
99106
}
100107

101108
@Test
@@ -110,12 +117,12 @@ class JdbcOperationsExtensionsTests {
110117
fun `queryForList with nullable reified type parameters`() {
111118
val list = listOf(1, null, 3)
112119
every { template.queryForList(sql, any<Class<Int>>()) } returns list
113-
assertThat(template.queryForList<Int?>(sql)).isEqualTo(list)
120+
assertThat(template.queryForList<Int>(sql)).isEqualTo(list)
114121
verify { template.queryForList(sql, any<Class<Int>>()) }
115122
}
116123

117124
@Test
118-
fun `queryForList with reified type parameters and argTypes`() {
125+
fun `queryForList with reified type parameters, non-null args and argTypes`() {
119126
val list = listOf(1, 2, 3)
120127
val args = arrayOf(3)
121128
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
@@ -125,31 +132,49 @@ class JdbcOperationsExtensionsTests {
125132
}
126133

127134
@Test
128-
fun `queryForList with nullable reified type parameters and argTypes`() {
135+
fun `queryForList with reified type parameters, nullable args and argTypes`() {
136+
val list = listOf(1, 2, 3)
137+
val args = arrayOf("foo", null)
138+
val argTypes = intArrayOf(JDBCType.VARCHAR.vendorTypeNumber)
139+
every { template.queryForList(sql, args, argTypes, any<Class<Int>>()) } returns list
140+
assertThat(template.queryForList<Int>(sql, args, argTypes)).isEqualTo(list)
141+
verify { template.queryForList(sql, args, argTypes, any<Class<Int>>()) }
142+
}
143+
144+
@Test
145+
fun `queryForList with nullable reified type parameters, non-null args and argTypes`() {
129146
val list = listOf(1, null, 3)
130147
val args = arrayOf(3)
131148
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
132149
every { template.queryForList(sql, args, argTypes, any<Class<Int>>()) } returns list
133-
assertThat(template.queryForList<Int?>(sql, args, argTypes)).isEqualTo(list)
150+
assertThat(template.queryForList<Int>(sql, args, argTypes)).isEqualTo(list)
151+
verify { template.queryForList(sql, args, argTypes, any<Class<Int>>()) }
152+
}
153+
154+
@Test
155+
fun `queryForList with nullable reified type parameters, nullable args and argTypes`() {
156+
val list = listOf(1, null, 3)
157+
val args = arrayOf("foo", null)
158+
val argTypes = intArrayOf(JDBCType.VARCHAR.vendorTypeNumber)
159+
every { template.queryForList(sql, args, argTypes, any<Class<Int>>()) } returns list
160+
assertThat(template.queryForList<Int>(sql, args, argTypes)).isEqualTo(list)
134161
verify { template.queryForList(sql, args, argTypes, any<Class<Int>>()) }
135162
}
136163

137164
@Test
138165
fun `queryForList with reified type parameters and args`() {
139166
val list = listOf(1, 2, 3)
140-
val args = arrayOf(3, 4)
141-
every { template.queryForList(sql, any<Class<Int>>(), args) } returns list
142-
template.queryForList<Int>(sql, args)
143-
verify { template.queryForList(sql, any<Class<Int>>(), args) }
167+
every { template.queryForList(sql, any<Class<Int>>(), 3, null) } returns list
168+
template.queryForList<Int>(sql, 3, null)
169+
verify { template.queryForList(sql, any<Class<Int>>(), 3, null) }
144170
}
145171

146172
@Test
147173
fun `queryForList with nullable reified type parameters and args`() {
148174
val list = listOf(1, null, 3)
149-
val args = arrayOf(3, 4)
150-
every { template.queryForList(sql, any<Class<Int>>(), args) } returns list
151-
template.queryForList<Int?>(sql, args)
152-
verify { template.queryForList(sql, any<Class<Int>>(), args) }
175+
every { template.queryForList(sql, any<Class<Int>>(), 3, null) } returns list
176+
template.queryForList<Int>(sql, 3, null)
177+
verify { template.queryForList(sql, any<Class<Int>>(), 3, null) }
153178
}
154179

155180
@Test

0 commit comments

Comments
 (0)