Migrating from V1 to V2
Stormify V2 is a major rewrite that brings Kotlin Multiplatform support, replacing the JVM-only V1. This guide covers all breaking changes and how to update your code.
What Changed
| Area | V1 | V2 |
|---|---|---|
| Platforms | JVM only | JVM, Android, Linux, Windows, iOS, macOS |
| Database access | JDBC directly | KDBC (wraps JDBC on JVM, native drivers elsewhere) |
| Initialization | Singleton (StormifyManager.stormify()) |
Constructor (Stormify(dataSource)) |
| Entity discovery | Reflection only | Reflection (JVM) + KSP code generation (native) |
| Exceptions | QueryException, SPParamException |
Unified SQLException |
| Stored procedures | SPParam with Mode enum |
Sp.In, Sp.Out<T>, Sp.InOut<T> |
| Coroutines | Not supported | SuspendStormify with connection pooling |
| Language | Java + optional Kotlin extensions | Kotlin (with Java interop on JVM) |
Dependencies
Maven
Gradle
The separate db and kotlin modules are merged into a single artifact delivered
by the Stormify Gradle plugin. The group ID changed from onl.ycode.stormify to
onl.ycode. The plugin is published to Maven Central — if plugin resolution
fails, add mavenCentral() to pluginManagement.repositories in
settings.gradle.kts. See Installation for configuration options.
Initialization
The global singleton is gone. Create Stormify instances via constructor.
Key change: instead of a global singleton, you hold a Stormify instance and pass it
to your services. This makes testing and multi-database setups straightforward.
Transactions
The transaction API moves from the static-singleton pattern to a plain lambda on a concrete instance. Every call inside the block automatically participates in the transaction, and nested transaction { } calls become savepoints.
Nested transactions use savepoints automatically:
stormify.transaction {
stormify.create(user)
stormify.transaction {
// Creates savepoint — rolls back only this block on failure
stormify.create(profile)
}
}
CRUD Operations
Method Signatures
// Reified generics — no Class parameter
val users = stormify.read<User>("SELECT * FROM users WHERE age > ?", 18)
val user = stormify.readOne<User>("SELECT * FROM users WHERE id = ?", 1)
val created = stormify.create(user) // Returns the created item
val updated = stormify.update(user) // Returns the updated item
stormify.delete(user)
Changes:
- No Class<T> parameter — V2 uses Kotlin reified generics
- create() and update() now return the item (useful for generated IDs)
- For Java callers, use StormifyJ which accepts Class<T> parameters
findById
Cursor-based Reading
V2 adds readCursor for processing large result sets without loading everything into memory:
stormify.readCursor<User>("SELECT * FROM users") { user ->
processUser(user) // Called for each row
}
Stored Procedures
The stored procedure API is redesigned for type safety.
Parameter types:
| V1 | V2 | Purpose |
|---|---|---|
SPParam(Mode.IN, value) |
Sp.In(value) or spIn(value) |
Input parameter |
SPParam(Mode.OUT, type) |
Sp.Out<T>() or spOut<T>() |
Output parameter |
SPParam(Mode.IN_OUT, value) |
Sp.InOut<T>(value) or spInOut(value) |
Bidirectional |
Exception Handling
V2 uses a single unified exception type across all platforms.
QueryException and SPParamException are removed. All database errors throw
onl.ycode.kdbc.SQLException.
Configuration
The naming policies and annotations (@DbTable, @DbField, @Id, @Table, @Column,
@Transient, etc.) are unchanged.
Entity Registration
On JVM via Maven, reflection-based entity discovery works the same as V1 (no changes
needed) — kotlin-reflect is now included as a transitive dependency.
On Gradle (all targets including JVM, Android, and Kotlin Multiplatform), the Stormify
Gradle plugin generates entity metadata at compile time. Pass the generated registrar
to the constructor: Stormify(dataSource, GeneratedEntities). See
Installation for details.
DataSource Wrapping (JVM)
On JVM, V2 accepts javax.sql.DataSource directly in the Stormify constructor (via a
convenience overload). If you need the KDBC DataSource interface explicitly:
The JdbcDataSource wrapper has zero overhead — it delegates directly to the underlying
JDBC types.
Removed APIs
The following V1 APIs no longer exist in V2:
onInit()callbacks — not needed; use constructor-based initialization instead.closeDataSource()/close()— Stormify no longer owns the DataSource. Close it directly.User::class.db(Kotlin table name extension) — removed. Usestormify.getTableInfo(User::class).tableNameinstead.storedProcedure()— renamed toprocedure().
Quick Migration Checklist
- Update dependencies:
onl.ycode.stormify:db→id("onl.ycode.stormify") version "2.6.0"(Gradle) oronl.ycode:stormify-jvm(Maven) - Replace singleton:
StormifyManager.stormify()→Stormify(dataSource)constructor - Hold the instance: pass
Stormifyto services instead of calling static methods - Update transactions:
stormify().transaction(() -> …)→stormify.transaction { … } - Remove Class parameters:
read(User.class, sql)→read<User>(sql) - Update exception handling:
QueryException→SQLException - Update stored procedures:
storedProcedure()→procedure(),SPParam→SpAPI - Add KSP if targeting native platforms
- Optional: adopt coroutine API for async workloads