Skip to content

Annotations

Stormify supports both its own annotations (@DbTable, @DbField) and standard JPA annotations (@Id, @Table, @Column, etc.) — see JPA annotations below.

@DbTable Annotation

The @DbTable annotation marks a Kotlin class as a Stormify entity. It serves two roles:

  1. Signals the class to the annotation processor so it emits the metadata registrar and type-safe PagedList paths (Foo_.name). This is required on Native/Android/iOS (no runtime reflection) and on any target that uses typed paths.
  2. Overrides the table name when the database table doesn't match the class name under the current naming policy.

When the table name already matches the policy (e.g. class User ↔ table user), use @DbTable without arguments as a pure marker. Provide name = "..." only when the database table name differs.

Attributes

  • name: Specifies the name of the table in the database. If not provided, the class name will be used, converted using the current naming policy.

Example

import onl.ycode.stormify.DbTable
import onl.ycode.stormify.DbField

// Marker only — table name is derived from the class name
@DbTable
data class User(
    @DbField(primaryKey = true)
    var id: Int = 0,
    var name: String = ""
)

// Explicit table name — different from what the naming policy would produce
@DbTable(name = "tbl_legacy_customer")
data class Customer(
    @DbField(primaryKey = true)
    var id: Int = 0,
    var name: String = ""
)
import onl.ycode.stormify.DbTable;
import onl.ycode.stormify.DbField;

// Marker only — table name is derived from the class name
@DbTable
public class User {
    @DbField(primaryKey = true)
    private int id;
    private String name;
    // getters and setters
}

// Explicit table name — different from what the naming policy would produce
@DbTable(name = "tbl_legacy_customer")
public class Customer {
    @DbField(primaryKey = true)
    private int id;
    private String name;
    // getters and setters
}

@DbField Annotation

The @DbField annotation provides additional information about a specific field. This annotation is optional and allows you to customize how fields are mapped to database columns.

Attributes

  • name: Specifies the name of the field in the database. If not provided, the field name in the class will be used, converted using the current naming policy.
  • primaryKey: Indicates whether the field is a primary key. Defaults to false.
  • primarySequence: Specifies the name of the primary key sequence in the database. If not provided, the primary key value generation relies on the database.
  • autoIncrement: Indicates the field value is auto-generated by the database (AUTO_INCREMENT, SERIAL, IDENTITY). When true, the field is excluded from INSERT statements and its value is read back after insertion. Defaults to false.
  • creatable: Determines whether the field can be used when creating a new record. Defaults to true.
  • updatable: Determines whether the field can be used when updating a record. Defaults to true.
  • enumAsString: When true, stores enum values as their string name instead of an integer. Defaults to false. See Enums.

Example

import onl.ycode.stormify.DbField

data class User(
    @DbField(name = "custom_id", primaryKey = true, primarySequence = "id_seq")
    var id: Int = 0,

    @DbField(creatable = false, updatable = true)
    var name: String = ""
)
import onl.ycode.stormify.DbField;

public class User {
    @DbField(name = "custom_id", primaryKey = true, primarySequence = "id_seq")
    private int id;

    @DbField(creatable = false, updatable = true)
    private String name;

    // getters and setters
}

In this example:

  • The id field is mapped to the custom_id column, marked as a primary key, and uses a sequence named id_seq.
  • The name field is configured to be updatable but not creatable.

Other Supported Annotations

Stormify provides support for several standard annotations from the javax.persistence package (JPA), making it easy to integrate with existing applications. The following annotations are supported:

  • @Id: Marks a field as the primary key of the entity.

  • @Table: Specifies the table in the database that maps to the entity. Stormify uses the table name from this annotation to map your classes to the corresponding database tables.

  • @Column: Maps a field to a specific column. Stormify reads the name, insertable, and updatable attributes.

  • @JoinColumn: Specifies the column used for joining an entity association. Stormify reads the name, insertable, and updatable attributes.

  • @SequenceGenerator: Defines a primary key generator that uses a database sequence, using the name attribute to specify the sequence name.

  • @GeneratedValue: When used with strategy = GenerationType.IDENTITY, marks a field as auto-generated by the database (equivalent to @DbField(autoIncrement = true)).

  • @Enumerated: Controls how enum fields are stored. @Enumerated(EnumType.STRING) stores the enum name as a string (equivalent to @DbField(enumAsString = true)). @Enumerated(EnumType.ORDINAL) (or omitting the annotation) stores the ordinal integer.

  • @Transient: Marks a field to be ignored during database operations. All three forms are supported: JPA @javax.persistence.Transient, Kotlin @kotlin.jvm.Transient, and the Java transient keyword.

These annotations help bridge the gap between your classes and the database schema. By leveraging standard JPA annotations, Stormify ensures compatibility with existing JPA setups while providing additional flexibility.

Annotation Processor (annproc)

Stormify needs entity metadata (field names, types, primary keys) to perform ORM operations. There are two ways to provide this metadata:

  • Reflection (JVM only): kotlin-reflect discovers metadata at runtime. This is the default — kotlin-reflect is included as a transitive dependency of stormify-jvm.
  • Annotation Processor: The annproc KSP processor generates metadata at compile time by scanning @DbTable and JPA @Entity annotations.

On Native/Android/iOS, reflection is not available — annproc is required. On JVM, annproc is optional but offers faster startup since metadata is pre-computed.

Setup

Add the KSP plugin and annproc dependency:

plugins {
    id("com.google.devtools.ksp") version "2.2.20-2.0.2"
}

dependencies {
    ksp("onl.ycode:annproc:2.0.0")
}
plugins {
    id 'com.google.devtools.ksp' version '2.2.20-2.0.2'
}

dependencies {
    ksp 'onl.ycode:annproc:2.0.0'
}

KSP requires the Kotlin compiler, so pure Java/Maven projects without a Kotlin compilation step cannot use annproc — they rely on kotlin-reflect instead.

The processor generates an EntityRegistrar object. Pass it to the Stormify constructor:

import db.stormify.GeneratedEntities

val stormify = Stormify(dataSource, GeneratedEntities)

Excluding kotlin-reflect

When using annproc on JVM, kotlin-reflect is no longer needed at runtime. You can exclude it to reduce the dependency footprint:

implementation("onl.ycode:stormify-jvm:2.0.0") {
    exclude(group = "org.jetbrains.kotlin", module = "kotlin-reflect")
}
implementation('onl.ycode:stormify-jvm:2.0.0') {
    exclude group: 'org.jetbrains.kotlin', module: 'kotlin-reflect'
}
<dependency>
    <groupId>onl.ycode</groupId>
    <artifactId>stormify-jvm</artifactId>
    <version>2.0.0</version>
    <exclusions>
        <exclusion>
            <groupId>org.jetbrains.kotlin</groupId>
            <artifactId>kotlin-reflect</artifactId>
        </exclusion>
    </exclusions>
</dependency>