Code Generator
This chapter introduces the Kronos code generator, which automatically generates entity classes from database tables.
Code Generator
Kronos code generator reads database metadata and writes Kotlin KPojo entity classes. Use it when the database schema is the source of truth and the project needs entity classes that match existing tables.
The generator uses a TOML config file and a Kotlin Script template. The config selects tables, data source, naming strategy, and output directory. The template controls the generated Kotlin file content.
For the Database First workflow, see Database First. For setup and runtime troubleshooting, see
📚Troubleshooting.
Dependencies Add script dependencies
Add kronos-codegen, kronos-core, and kronos-jdbc-wrapper to the .main.kts script. Add the JDBC driver and connection pool that match your database and JDK.
example.main.kts
#!/usr/bin/env kotlin
@file:Repository("https://repo1.maven.org/maven2")
@file:DependsOn("com.kotlinorm:kronos-codegen:0.4.0")
@file:DependsOn("com.kotlinorm:kronos-core:0.4.0")
@file:DependsOn("com.kotlinorm:kronos-jdbc-wrapper:0.4.0")
@file:DependsOn("org.apache.commons:commons-dbcp2:<latest-stable>")
@file:DependsOn("com.mysql:mysql-connector-j:<latest-stable>")Replace <latest-stable> with the current stable version from the connection pool or JDBC driver project.
Configuration Select tables
Create config.toml. Each [[table]] item becomes one Kotlin file.
config.toml
[[table]]
name = "tb_user"
className = "User"
[[table]]
name = "tb_order"
className = "Order"With the output config below, the generator writes one file per table.
generated files
src/main/kotlin/com/example/entity/User.kt
src/main/kotlin/com/example/entity/Order.ktSet className when the Kotlin class name should be controlled explicitly.
class name
[[table]]
name = "sys_account"
className = "Account"Configure output
targetDir selects the generated file directory. packageName selects the package declaration written by the template.
config.toml
[output]
targetDir = "src/main/kotlin/com/example/entity"
packageName = "com.example.entity"
tableCommentLineWords = 80The template can read these values directly.
template
template {
+"package $packageName"
+""
+formatedComment
}The generated file starts with the configured package and the formatted table comment.
User.kt
package com.example.entity
// User account tableConfigure a data source
dataSource creates the JDBC connection used to read table comments, columns, and indexes. This example uses Apache DBCP2 and the built-in KronosJdbcWrapper.
config.toml
[dataSource]
wrapperClassName = "com.kotlinorm.wrappers.KronosJdbcWrapper"
dataSourceClassName = "org.apache.commons.dbcp2.BasicDataSource"
url = "jdbc:mysql://localhost:3306/kronos_demo?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=false"
username = "root"
password = "your_password"
driverClassName = "com.mysql.cj.jdbc.Driver"
initialSize = 5
maxTotal = 10Use the property names supported by the selected DataSource class.
Druid
[dataSource]
wrapperClassName = "com.kotlinorm.wrappers.KronosJdbcWrapper"
dataSourceClassName = "com.alibaba.druid.pool.DruidDataSource"
url = "jdbc:mysql://localhost:3306/kronos_demo"
username = "root"
password = "your_password"
driverClassName = "com.mysql.cj.jdbc.Driver"
initialSize = 5
maxActive = 10Add the matching pool dependency to the script when you switch the pool implementation.
Druid dependency
@file:DependsOn("com.alibaba:druid:<latest-stable>")Configure naming
lineHumpNamingStrategy maps underscore names to camel-case Kotlin property names.
config.toml
[strategy]
tableNamingStrategy = "lineHumpNamingStrategy"
fieldNamingStrategy = "lineHumpNamingStrategy"With this strategy, a database column named create_time is generated as createTime.
User.kt
var createTime: java.time.LocalDateTime? = nullUse noneNamingStrategy when the generated name should keep the database metadata name.
keep names
[strategy]
tableNamingStrategy = "noneNamingStrategy"
fieldNamingStrategy = "noneNamingStrategy"User.kt
var create_time: java.time.LocalDateTime? = nullGenerate special field annotations
Add strategy fields for primary key, create time, update time, logic delete, and optimistic lock columns.
config.toml
[strategy]
primaryKeyStrategy = "id"
createTimeStrategy = "create_time"
updateTimeStrategy = "update_time"
logicDeleteStrategy = "deleted"
optimisticLockStrategy = "version"When the database table contains matching columns, field.annotations() writes the Kronos annotations. The logical-delete column must define DEFAULT 0 (DEFAULT false on PostgreSQL) for Codegen to emit the @Default annotation shown below.
User.kt
import com.kotlinorm.annotations.CreateTime
import com.kotlinorm.annotations.Default
import com.kotlinorm.annotations.LogicDelete
import com.kotlinorm.annotations.PrimaryKey
import com.kotlinorm.annotations.UpdateTime
import com.kotlinorm.annotations.Version
data class User(
@PrimaryKey(identity = true)
var id: Int? = null,
@CreateTime
var createTime: java.time.LocalDateTime? = null,
@UpdateTime
var updateTime: java.time.LocalDateTime? = null,
@LogicDelete
@Default("0") // @Default("false") for Postgres
var deleted: Boolean? = null,
@Version
var version: Int? = null
) : KPojoFor annotation behavior in ORM operations, see 📚Annotation Config.
Generate column metadata annotations
The template can turn database metadata into field annotations. A non-null database column is generated with @NonNull.
template
fields.forEach { field ->
field.annotations().forEach { annotation ->
+"""${indent(4)}$annotation"""
}
+"""${indent(4)}var ${field.name}: ${field.kotlinType}? = null,"""
}For a required name column, the generated property includes @NonNull.
User.kt
@NonNull
var name: String? = nullA decimal column with precision metadata is generated with @ColumnType.
User.kt
@ColumnType(type = KColumnType.DECIMAL, length = 10, scale = 2)
var balance: java.math.BigDecimal? = nullGenerate table indexes
Use indexes.toAnnotations() to write index annotations collected from the database metadata.
template
+indexes.toAnnotations()
+"""@Table("$tableName")"""The generated entity includes @TableIndex before the class declaration.
User.kt
@TableIndex(name = "idx_user_email", columns = ["email"], type = "UNIQUE")
@Table("tb_user")
data class User(
var email: String? = null
) : KPojoCreate the template
Call init("config.toml") before template { ... }. The template block runs once for each configured table.
example.main.kts
import com.kotlinorm.codegen.KronosConfig.Companion.write
import com.kotlinorm.codegen.TemplateConfig.Companion.template
import com.kotlinorm.codegen.init
import com.kotlinorm.codegen.kotlinType
init("config.toml")
template {
+"package $packageName"
+""
+imports.joinToString("
") { "import $it" }
+""
+formatedComment
+indexes.toAnnotations()
+"""@Table("$tableName")"""
+"""data class $className("""
+fields.mapIndexed { index, field ->
val annotations = field.annotations().joinToString("
") { "${indent(4)}$it" }
val annotationBlock = if (annotations.isEmpty()) "" else "$annotations
"
val comma = if (index == fields.lastIndex) "" else ","
"""$annotationBlock${indent(4)}var ${field.name}: ${field.kotlinType}? = null$comma"""
}.joinToString("
")
+") : KPojo"
}.write()The generated file follows the structure assembled by the template.
User.kt
package com.example.entity
import com.kotlinorm.annotations.Table
import com.kotlinorm.interfaces.KPojo
@Table("tb_user")
data class User(
var id: Int? = null,
var name: String? = null
) : KPojoUse config inheritance
Put shared output and data source settings in a base TOML file.
base.toml
[output]
targetDir = "src/main/kotlin/com/example/entity"
packageName = "com.example.entity"
[dataSource]
wrapperClassName = "com.kotlinorm.wrappers.KronosJdbcWrapper"
dataSourceClassName = "org.apache.commons.dbcp2.BasicDataSource"
url = "jdbc:mysql://localhost:3306/kronos_demo"
username = "root"
password = "your_password"
driverClassName = "com.mysql.cj.jdbc.Driver"The project config can extend the base file and add its own table list.
config.toml
extend = "base.toml"
[[table]]
name = "tb_user"
className = "User"Run the script with the project config.
example.main.kts
init("config.toml")Run the generator
Kotlin script files should use the xxx.main.kts name format.
shell
kotlinc -script example.main.ktsAfter a successful run, the generator logs each written file.
output
File generated successfully: src/main/kotlin/com/example/entity/User.ktIf the config misses a required section, the script exits with a clear message.
missing table
IllegalArgumentException: Table configuration is required in config: config.toml