Infer Kotlin null-safety from type variables

This commit removes the constraint from type variables in
PropertyResolver, JdbcOperations and RestOperations
Kotlin extensions in order to get null-safety inferred
from the type declared by the user.

Closes gh-22687
This commit is contained in:
Sebastien Deleuze
2019-03-27 08:50:42 +01:00
parent 68a529b915
commit cbb5a78aa0
6 changed files with 175 additions and 124 deletions

View File

@@ -16,9 +16,11 @@
package org.springframework.jdbc.core
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Test
import java.sql.*
@@ -30,91 +32,96 @@ import java.sql.*
*/
class JdbcOperationsExtensionsTests {
val template = mockk<JdbcTemplate>(relaxed = true)
val template = mockk<JdbcTemplate>()
val sql = "select age from customer where id = 3"
@Test
fun `queryForObject with reified type parameters`() {
val sql = "select age from customer where id = 3"
template.queryForObject<Int>(sql)
verify { template.queryForObject(sql, Integer::class.java) }
every { template.queryForObject(sql, any<Class<Int>>()) } returns 2
assertEquals(2, template.queryForObject<Int>(sql))
verify { template.queryForObject(sql, any<Class<Int>>()) }
}
@Test
fun `queryForObject with RowMapper-like function`() {
val sql = "select age from customer where id = ?"
template.queryForObject(sql, 3) { rs: ResultSet, _: Int -> rs.getInt(1) }
every { template.queryForObject(sql, any<RowMapper<Int>>(), any<Int>()) } returns 2
assertEquals(2, template.queryForObject(sql, 3) { rs: ResultSet, _: Int -> rs.getInt(1) })
verify { template.queryForObject(eq(sql), any<RowMapper<Int>>(), eq(3)) }
}
@Test // gh-22682
fun `queryForObject with nullable RowMapper-like function`() {
val sql = "select age from customer where id = ?"
template.queryForObject(sql, 3) { _, _ -> null as Int? }
every { template.queryForObject(sql, any<RowMapper<Int>>(), 3) } returns null
assertNull(template.queryForObject(sql, 3) { _, _ -> null as Int? })
verify { template.queryForObject(eq(sql), any<RowMapper<Int?>>(), eq(3)) }
}
@Test
fun `queryForObject with reified type parameters and argTypes`() {
val sql = "select age from customer where id = ?"
val args = arrayOf(3)
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
template.queryForObject<Int>(sql, args, argTypes)
verify { template.queryForObject(sql, args, argTypes, Integer::class.java) }
every { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) } returns 2
assertEquals(2, template.queryForObject<Int>(sql, args, argTypes))
verify { template.queryForObject(sql, args, argTypes, any<Class<Int>>()) }
}
@Test
fun `queryForObject with reified type parameters and args`() {
val sql = "select age from customer where id = ?"
val args = arrayOf(3)
template.queryForObject<Int>(sql, args)
verify { template.queryForObject(sql, args, Integer::class.java) }
every { template.queryForObject(sql, args, any<Class<Int>>()) } returns 2
assertEquals(2, template.queryForObject<Int>(sql, args))
verify { template.queryForObject(sql, args, any<Class<Int>>()) }
}
@Test
fun `queryForList with reified type parameters`() {
val sql = "select age from customer where id = 3"
template.queryForList<Int>(sql)
verify { template.queryForList(sql, Integer::class.java) }
val list = listOf(1, 2, 3)
every { template.queryForList(sql, any<Class<Int>>()) } returns list
assertEquals(list, template.queryForList<Int>(sql))
verify { template.queryForList(sql, any<Class<Int>>()) }
}
@Test
fun `queryForList with reified type parameters and argTypes`() {
val sql = "select age from customer where id = ?"
val list = listOf(1, 2, 3)
val args = arrayOf(3)
val argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber)
template.queryForList<Int>(sql, args, argTypes)
verify { template.queryForList(sql, args, argTypes, Integer::class.java) }
every { template.queryForList(sql, args, argTypes, any<Class<Int>>()) } returns list
assertEquals(list, template.queryForList<Int>(sql, args, argTypes))
verify { template.queryForList(sql, args, argTypes, any<Class<Int>>()) }
}
@Test
fun `queryForList with reified type parameters and args`() {
val sql = "select age from customer where id = ?"
val list = listOf(1, 2, 3)
val args = arrayOf(3)
every { template.queryForList(sql, args, any<Class<Int>>()) } returns list
template.queryForList<Int>(sql, args)
verify { template.queryForList(sql, args, Integer::class.java) }
verify { template.queryForList(sql, args, any<Class<Int>>()) }
}
@Test
fun `query with ResultSetExtractor-like function`() {
val sql = "select age from customer where id = ?"
template.query<Int>(sql, 3) { rs ->
every { template.query(eq(sql), any<ResultSetExtractor<Int>>(), eq(3)) } returns 2
assertEquals(2, template.query<Int>(sql, 3) { rs ->
rs.next()
rs.getInt(1)
}
})
verify { template.query(eq(sql), any<ResultSetExtractor<Int>>(), eq(3)) }
}
@Test // gh-22682
fun `query with nullable ResultSetExtractor-like function`() {
val sql = "select age from customer where id = ?"
template.query<Int?>(sql, 3) { _ -> null }
every { template.query(eq(sql), any<ResultSetExtractor<Int?>>(), eq(3)) } returns null
assertNull(template.query<Int?>(sql, 3) { _ -> null })
verify { template.query(eq(sql), any<ResultSetExtractor<Int?>>(), eq(3)) }
}
@Suppress("RemoveExplicitTypeArguments")
@Test
fun `query with RowCallbackHandler-like function`() {
val sql = "select age from customer where id = ?"
every { template.query(sql, ofType<RowCallbackHandler>(), 3) } returns Unit
template.query(sql, 3) { rs ->
assertEquals(22, rs.getInt(1))
}
@@ -123,10 +130,11 @@ class JdbcOperationsExtensionsTests {
@Test
fun `query with RowMapper-like function`() {
val sql = "select age from customer where id = ?"
template.query(sql, 3) { rs, _ ->
val list = listOf(1, 2, 3)
every { template.query(sql, ofType<RowMapper<*>>(), 3) } returns list
assertEquals(list, template.query(sql, 3) { rs, _ ->
rs.getInt(1)
}
})
verify { template.query(sql, ofType<RowMapper<*>>(), 3) }
}