Add Kotlin JDBC extensions
Issue: SPR-15158
This commit is contained in:
committed by
Sebastien Deleuze
parent
9666fcc41d
commit
c33ad15b28
@@ -678,6 +678,8 @@ project("spring-jdbc") {
|
||||
optional("com.h2database:h2:1.4.193")
|
||||
optional("org.apache.derby:derby:10.13.1.1")
|
||||
optional("org.apache.derby:derbyclient:10.13.1.1")
|
||||
optional("org.jetbrains.kotlin:kotlin-reflect:${kotlinVersion}")
|
||||
optional("org.jetbrains.kotlin:kotlin-stdlib:${kotlinVersion}")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core
|
||||
|
||||
import java.sql.ResultSet
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForObject] providing a [KClass] based variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.queryForObject(sql: String, elementType: KClass<T>): T = queryForObject(sql, elementType.java)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForObject] providing a `queryForObject<Foo>("...")` variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
inline fun <reified T : Any> JdbcOperations.queryForObject(sql: String): T = queryForObject(sql, T::class.java)
|
||||
|
||||
/**
|
||||
* Extensions for [JdbcOperations.queryForObject] providing a RowMapper-like function variant: `queryForObject("...", arg1, argN){ rs, i -> }`.
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.queryForObject(sql: String, vararg args: Any, function: (ResultSet, Int) -> T): T =
|
||||
queryForObject(sql, RowMapper { resultSet, i -> function(resultSet, i) }, *args)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForObject] providing a [KClass] based variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.queryForObject(sql: String, args: Array<out Any>, argTypes: IntArray, requiredType: KClass<T>): T =
|
||||
queryForObject(sql, args, argTypes, requiredType.java)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForObject] providing a `queryForObject<Foo>("...", arrayOf(arg1, argN), intArray(type1, typeN))` variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
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 [KClass] based variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.queryForObject(sql: String, args: Array<out Any>, requiredType: KClass<T>): T =
|
||||
queryForObject(sql, args, requiredType.java)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForObject] providing a `queryForObject<Foo>("...", arrayOf(arg1, argN))` variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
inline fun <reified T : Any> JdbcOperations.queryForObject(sql: String, args: Array<out Any>): T =
|
||||
queryForObject(sql, args, T::class.java)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForObject] providing a [KClass] based variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.queryForObject(sql: String, requiredType: KClass<T>, vararg args: Any): T =
|
||||
queryForObject(sql, requiredType.java, *args)
|
||||
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForList] providing a [KClass] based variant.
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.queryForList(sql: String, elementType: KClass<T>): List<T> =
|
||||
queryForList(sql, elementType.java)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForList] providing a `queryForList<Foo>("...")` variant.
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
inline fun <reified T : Any> JdbcOperations.queryForList(sql: String): List<T> =
|
||||
queryForList(sql, T::class.java)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForList] providing a [KClass] based variant.
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.queryForList(sql: String, args: Array<out Any>, argTypes: IntArray, elementType: KClass<T>): List<T> =
|
||||
queryForList(sql, args, argTypes, elementType.java)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForList] providing a `queryForList<Foo>("...", arrayOf(arg1, argN), intArray(type1, typeN))` variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
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 [KClass] based variant.
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.queryForList(sql: String, args: Array<out Any>, elementType: KClass<T>): List<T> =
|
||||
queryForList(sql, args, elementType.java)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.queryForList] providing a `queryForList<Foo>("...", arrayOf(arg1, argN))` variant
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
inline fun <reified T : Any> JdbcOperations.queryForList(sql: String, args: Array<out Any>): List<T> =
|
||||
queryForList(sql, args, T::class.java)
|
||||
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.query] providing a ResultSetExtractor-like function variant: `query<Foo>("...", arg1, argN){ rs -> }`
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
inline fun <reified T : Any> JdbcOperations.query(sql: String, vararg args: Any, crossinline function: (ResultSet) -> T): T =
|
||||
query(sql, ResultSetExtractor { function(it) }, *args)
|
||||
|
||||
/**
|
||||
* Extension for [JdbcOperations.query] providing a RowCallbackHandler-like function variant: `query("...", arg1, argN){ rs -> }`
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet) -> Unit): Unit =
|
||||
query(sql, RowCallbackHandler { function(it) }, *args)
|
||||
|
||||
/**
|
||||
* Extensions for [JdbcOperations.query] providing a RowMapper-like function variant: `query("...", arg1, argN){ rs, i -> }`.
|
||||
*
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*/
|
||||
fun <T : Any> JdbcOperations.query(sql: String, vararg args: Any, function: (ResultSet, Int) -> T): List<T> =
|
||||
query(sql, RowMapper { rs, i -> function(rs, i) }, *args)
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam
|
||||
|
||||
/**
|
||||
* Extension for [MapSqlParameterSource.addValue] providing Array like setter
|
||||
*
|
||||
* ```kotlin
|
||||
* source["age"] = 3
|
||||
* ```
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*
|
||||
*/
|
||||
operator fun MapSqlParameterSource.set(paramName: String, value: Any) {
|
||||
this.addValue(paramName, value)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension for [MapSqlParameterSource.addValue] providing Array like setter
|
||||
*
|
||||
* ```kotlin
|
||||
* source["age", JDBCType.INTEGER.vendorTypeNumber] = 3
|
||||
* ```
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*
|
||||
*/
|
||||
operator fun MapSqlParameterSource.set(paramName: String, sqlType: Int, value: Any) {
|
||||
this.addValue(paramName, value, sqlType)
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension for [MapSqlParameterSource.addValue] providing Array like setter
|
||||
*
|
||||
* ```kotlin
|
||||
* source["age", JDBCType.INTEGER.vendorTypeNumber, "INT"] = 3
|
||||
* ```
|
||||
* @author Mario Arias
|
||||
* @since 5.0
|
||||
*
|
||||
*/
|
||||
operator fun MapSqlParameterSource.set(paramName: String, sqlType: Int, typeName: String, value: Any) {
|
||||
this.addValue(paramName, value, sqlType, typeName)
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core
|
||||
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Before
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.ExpectedException
|
||||
import org.mockito.ArgumentMatchers.anyString
|
||||
import org.mockito.BDDMockito.given
|
||||
import org.mockito.Mockito.mock
|
||||
import java.sql.*
|
||||
import javax.sql.DataSource
|
||||
|
||||
/**
|
||||
* Mock object based tests for JdbcOperationsExtension
|
||||
*/
|
||||
class JdbcOperationsExtensionsTests {
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val thrown = ExpectedException.none()!!
|
||||
|
||||
lateinit private var connection: Connection
|
||||
lateinit private var dataSource: DataSource
|
||||
lateinit private var preparedStatement: PreparedStatement
|
||||
lateinit private var statement: Statement
|
||||
lateinit private var resultSet: ResultSet
|
||||
lateinit private var template: JdbcTemplate
|
||||
lateinit private var callableStatement: CallableStatement
|
||||
lateinit private var resultSetMetaData: ResultSetMetaData
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
connection = mock(Connection::class.java)
|
||||
dataSource = mock(DataSource::class.java)
|
||||
preparedStatement = mock(PreparedStatement::class.java)
|
||||
statement = mock(Statement::class.java)
|
||||
resultSet = mock(ResultSet::class.java)
|
||||
callableStatement = mock(CallableStatement::class.java)
|
||||
resultSetMetaData = mock(ResultSetMetaData::class.java)
|
||||
template = JdbcTemplate(dataSource)
|
||||
given(dataSource.connection).willReturn(connection)
|
||||
given(connection.prepareStatement(anyString())).willReturn(preparedStatement)
|
||||
given(preparedStatement.executeQuery()).willReturn(resultSet)
|
||||
given(preparedStatement.executeQuery(anyString())).willReturn(resultSet)
|
||||
given(preparedStatement.connection).willReturn(connection)
|
||||
given(statement.connection).willReturn(connection)
|
||||
given(statement.executeQuery(anyString())).willReturn(resultSet)
|
||||
given(connection.prepareCall(anyString())).willReturn(callableStatement)
|
||||
given(connection.createStatement()).willReturn(statement)
|
||||
given(callableStatement.resultSet).willReturn(resultSet)
|
||||
given(resultSetMetaData.columnCount).willReturn(1)
|
||||
given(resultSetMetaData.getColumnName(1)).willReturn("age")
|
||||
given(resultSet.metaData).willReturn(resultSetMetaData)
|
||||
given(resultSet.next()).willReturn(true, false)
|
||||
given(resultSet.getInt(1)).willReturn(22)
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
fun `queryForObject with KClass`() {
|
||||
val i = template.queryForObject("select age from customer where id = 3", Int::class)
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForObject with reified type`() {
|
||||
val i: Int = template.queryForObject("select age from customer where id = 3")
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForObject with RowMapper-like function`() {
|
||||
val i = template.queryForObject("select age from customer where id = ?", 3) { rs, i ->
|
||||
rs.getInt(1)
|
||||
}
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForObject with argTypes`() {
|
||||
val i = template.queryForObject("select age from customer where id = ?", arrayOf(3),
|
||||
intArrayOf(JDBCType.INTEGER.vendorTypeNumber), Int::class)
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForObject with reified type and argTypes`() {
|
||||
val i: Int = template.queryForObject("select age from customer where id = ?", arrayOf(3),
|
||||
intArrayOf(JDBCType.INTEGER.vendorTypeNumber))
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForObject with args`() {
|
||||
val i = template.queryForObject("select age from customer where id = ?", arrayOf(3), Int::class)
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForObject with reified type and args`() {
|
||||
val i: Int = template.queryForObject("select age from customer where id = ?", arrayOf(3))
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForObject with varargs`() {
|
||||
val i = template.queryForObject("select age from customer where id = ?", Int::class, 3)
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForList with KClass`() {
|
||||
val i = template.queryForList(sql = "select age from customer where id = 3", elementType = Int::class)
|
||||
assertEquals(22, i.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForList with reified type`() {
|
||||
val i = template.queryForList<Int>("select age from customer where id = 3")
|
||||
assertEquals(22, i.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForList with argTypes`() {
|
||||
val i = template.queryForList(sql = "select age from customer where id = ?", args = arrayOf(3),
|
||||
argTypes = intArrayOf(JDBCType.INTEGER.vendorTypeNumber), elementType = Int::class)
|
||||
assertEquals(22, i.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForList with reified type and argTypes`() {
|
||||
val i = template.queryForList<Int>("select age from customer where id = ?", arrayOf(3), intArrayOf(JDBCType.INTEGER.vendorTypeNumber))
|
||||
assertEquals(22, i.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForList with args`() {
|
||||
val i = template.queryForList(sql = "select age from customer where id = ?", args = arrayOf(3), elementType = Int::class)
|
||||
assertEquals(22, i.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `queryForList with reified type and args`() {
|
||||
val i = template.queryForList<Int>("select age from customer where id = ?", arrayOf(3))
|
||||
assertEquals(22, i.first())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `query with ResultSetExtractor-like function`() {
|
||||
val i = template.query<Int>("select age from customer where id = ?", 3) { rs ->
|
||||
rs.next()
|
||||
rs.getInt(1)
|
||||
}
|
||||
assertEquals(22, i)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `query with RowCallbackHandler-like function`() {
|
||||
template.query("select age from customer where id = ?", 3) { rs ->
|
||||
assertEquals(22, rs.getInt(1))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `query with RowMapper-like function`() {
|
||||
val i = template.query("select age from customer where id = ?", 3) { rs, i ->
|
||||
rs.getInt(1)
|
||||
}
|
||||
assertEquals(22, i.first())
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.jdbc.core.namedparam
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
import java.sql.JDBCType
|
||||
|
||||
/**
|
||||
* @author Mario Arias
|
||||
*/
|
||||
class MapSqlParameterSourceExtensionsTests {
|
||||
|
||||
@Test
|
||||
fun `setter with value`() {
|
||||
val source = MapSqlParameterSource()
|
||||
source["foo"] = 2
|
||||
assertEquals(2, source.getValue("foo"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setter with value and type`() {
|
||||
val source = MapSqlParameterSource()
|
||||
source["foo", JDBCType.INTEGER.vendorTypeNumber] = 2
|
||||
assertEquals(2, source.getValue("foo"))
|
||||
assertEquals(JDBCType.INTEGER.vendorTypeNumber, source.getSqlType("foo"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `setter with value, type and type name`() {
|
||||
val source = MapSqlParameterSource()
|
||||
source["foo", JDBCType.INTEGER.vendorTypeNumber, "INT"] = 2
|
||||
assertEquals(2, source.getValue("foo"))
|
||||
assertEquals(JDBCType.INTEGER.vendorTypeNumber, source.getSqlType("foo"))
|
||||
assertEquals("INT", source.getTypeName("foo"))
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user