Data Sources and Third-party Framework
Kronos can be easily used with third-party frameworks by customizing the creation of wrapper classes that inherit the KronosDataSourceWrapper interface.
Native drivers
Implement KronosExecutionDataSource for a platform driver and wrap it with KronosExecutionWrapper to execute shared ORM queries. See 📚Native SQLite for the complete connection example.
Build a wrapper for an existing framework
KronosDataSourceWrapper lets Kronos use an execution layer that already exists in your project. A wrapper receives Kronos SQL tasks and delegates them to the framework's query, update, batch, and transaction APIs.
For the full interface contract, see 📚Data source wrapper.
Android SQLite reference
The dedicated 📚Android SQLite chapter provides Android/JVM SQLiteDatabase setup and a complete wrapper reference.
Add Spring JDBC and Kronos
Spring Boot projects usually manage Spring dependency versions through the selected Boot version. Use the latest stable JDBC driver that matches your database server and JDK.
maven
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>com.kotlinorm</groupId>
<artifactId>kronos-core</artifactId>
<version>0.4.0</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql-connector-j.version}</version>
</dependency>
</dependencies>gradle(kts)
dependencies {
implementation("org.springframework.boot:spring-boot-starter-jdbc")
implementation("com.kotlinorm:kronos-core:0.4.0")
implementation("com.mysql:mysql-connector-j:<latest-stable>")
}Read metadata from DataSource
The wrapper exposes url, userName, and dbType from JDBC metadata. Kronos uses dbType to select SQL rendering and table statements.
metadata
class SpringJdbcKronosWrapper(
private val dataSource: DataSource
) : KronosDataSourceWrapper {
override val url: String
override val userName: String
override val dbType: DBType
private val namedJdbc = NamedParameterJdbcTemplate(dataSource)
private val transactionManager = DataSourceTransactionManager(dataSource)
init {
dataSource.connection.use { conn ->
url = conn.metaData.url
userName = conn.metaData.userName ?: ""
dbType = DBType.fromName(conn.metaData.databaseProductName)
}
}
}Delegate queries
KAtomicQueryTask.sql uses named parameters, paramMap contains the values, and targetType is the complete requested KType. A custom wrapper implements one list method and one first-row method for maps, scalar values, KPojo classes, and DTOs.
query mapping
import kotlin.reflect.jvm.jvmErasure
private fun rowMapper(targetType: KType): RowMapper<Any?> {
val targetClass = targetType.jvmErasure
return when {
targetClass == Map::class -> ColumnMapRowMapper()
targetClass in setOf(String::class, Int::class, Long::class, Boolean::class) ->
SingleColumnRowMapper(targetClass.java)
else -> DataClassRowMapper(targetClass.java)
}
}
override fun toList(task: KAtomicQueryTask): List<Any?> =
namedJdbc.query(task.sql, task.paramMap, rowMapper(task.targetType))
override fun first(task: KAtomicQueryTask): Any? =
toList(task).firstOrNull()query usage
val users = wrapper.toList(
KronosAtomicQueryTask(
sql = "SELECT id, name FROM user WHERE status = :status",
paramMap = mapOf("status" to "ACTIVE"),
targetType = typeOf<User>()
)
)Delegate writes
KAtomicActionTask carries one parameter map. KronosAtomicBatchTask carries one SQL statement and multiple parameter maps.
writes
override fun update(task: KAtomicActionTask): Int {
return namedJdbc.update(task.sql, task.paramMap)
}
override fun batchUpdate(task: KronosAtomicBatchTask): IntArray {
return namedJdbc.batchUpdate(task.sql, task.paramMapArr ?: emptyArray())
}write usage
val affectedRows = wrapper.batchUpdate(
KronosAtomicBatchTask(
sql = "UPDATE user SET status = :status WHERE id = :id",
paramMapArr = arrayOf(
mapOf("status" to "ACTIVE", "id" to 1),
mapOf("status" to "LOCKED", "id" to 2)
)
)
)Delegate transactions
transact(...) receives Kronos transaction options and runs the block with TransactionScope. Passing the Spring-managed JDBC connection enables TransactionScope savepoints.
transaction
override fun transact(
isolation: TransactionIsolation?,
timeout: Int?,
block: TransactionScope.() -> Any?
): Any? {
val definition = DefaultTransactionDefinition().apply {
isolation?.let { isolationLevel = it.level }
timeout?.let { this.timeout = it }
}
return TransactionTemplate(transactionManager, definition).execute {
val connection = DataSourceUtils.getConnection(dataSource)
try {
TransactionScope(connection).block()
} finally {
DataSourceUtils.releaseConnection(connection, dataSource)
}
}
}transaction usage
wrapper.transact(timeout = 30) {
val point = savepoint("before_status_update")
try {
wrapper.update(
KronosAtomicActionTask(
sql = "UPDATE user SET status = :status WHERE id = :id",
paramMap = mapOf("status" to "ACTIVE", "id" to 1)
)
)
releaseSavepoint(point)
} catch (e: Exception) {
rollbackToSavepoint(point)
throw e
}
}Register the wrapper
Register the wrapper once during application startup, or expose it as a Spring bean and assign it where your application initializes Kronos.
register
@Bean
fun kronosWrapper(dataSource: DataSource): KronosDataSourceWrapper {
return SpringJdbcKronosWrapper(dataSource)
}
@Bean
fun kronosConfiguration(wrapper: KronosDataSourceWrapper): Any {
Kronos.dataSource = { wrapper }
return Any()
}Use frameworks with positional parameters
Frameworks that execute JDBC ? parameters can use task.parsed() and KronosAtomicBatchTask.parsedArr().
single task
val task = KronosAtomicActionTask(
sql = "UPDATE user SET status = :status WHERE id = :id",
paramMap = mapOf("status" to "ACTIVE", "id" to 1)
)
val (jdbcSql, params) = task.parsed()
println(jdbcSql)
println(params.toList())output
UPDATE user SET status = ? WHERE id = ?
[ACTIVE, 1]batch task
val (jdbcSql, paramList) = batchTask.parsedArr()
paramList.forEach { params ->
preparedStatement.setObject(1, params[0])
preparedStatement.setObject(2, params[1])
preparedStatement.addBatch()
}The built-in JDBC implementation is a complete reference for positional parameter execution: KronosJdbcWrapper.kt.