Skip to content

Java / Kotlin

The JVM and Kotlin bindings are not on Maven Central yet. Build them from the repository and install into your local Maven repository:

Terminal window
git clone https://github.com/russellromney/honker
cd honker
cargo build --release -p honker-extension # the loadable extension
mvn -f packages/honker-jvm/pom.xml install
mvn -f packages/honker-kotlin/pom.xml install # only if you want the Kotlin helpers

Then depend on the installed artifacts.

Java:

<dependency>
<groupId>dev.honker</groupId>
<artifactId>honker</artifactId>
<version>0.5.0</version>
</dependency>

Kotlin:

<dependency>
<groupId>dev.honker</groupId>
<artifactId>honker-kotlin</artifactId>
<version>0.5.0</version>
</dependency>

The Java artifact is the runtime binding. The Kotlin artifact adds builder DSLs, typed extension helpers, coroutine Flow wrappers, and suspending task-result helpers over that same runtime.

If you would rather not build anything, the JVM can use Honker as a plain SQLite extension over JDBC instead — download it from the latest release and follow the JVM ORM guide. That path needs no Maven install.

Java:

import dev.honker.Honker;
import dev.honker.OpenOptions;
import dev.honker.WatcherBackend;
import dev.honker.WatcherOptions;
var options = OpenOptions.builder()
.watcherOptions(WatcherOptions.builder()
.backend(WatcherBackend.MMAP_SHM)
.build())
.build();
try (var db = Honker.open("app.db", options)) {
// use db
}

Kotlin:

import dev.honker.WatcherBackend
import dev.honker.kotlin.honker
import dev.honker.kotlin.openOptions
import dev.honker.kotlin.watcherOptions
honker("app.db", openOptions {
watcherOptions(watcherOptions {
backend(WatcherBackend.MMAP_SHM)
})
}).use { db ->
// use db
}

WatcherBackend.AUTO and PRAGMA_DATA_VERSION use the stable pragma watcher. MMAP_SHM and KERNEL_EVENTS are explicit experimental backends. Unlike the Rust, Go, .NET, Ruby, and Elixir bindings — which fail at open — the JVM watcher is created lazily, so a failed experimental backend surfaces when a subscriber attaches (via throwIfFailed on the listener/stream handles), not at Honker.open().

try (var db = Honker.open("app.db")) {
var q = db.queue("emails");
q.enqueue("{\"to\":\"alice@example.com\",\"order_id\":42}");
var job = q.claimOne("worker-1").orElseThrow();
sendEmail(job.payloadJson());
job.ack();
}

Kotlin can consume jobs as a coroutine flow:

import dev.honker.kotlin.asFlow
import dev.honker.kotlin.honker
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.runBlocking
runBlocking {
honker("app.db").use { db ->
db.queue("emails").asFlow("worker-1").collect { job ->
sendEmail(job.payloadJson())
job.ack()
}
}
}

Java and Kotlin provide first-class named task registries, task handles, workers, and stored results. Registration is explicit: the Java runtime does not scan annotations, and the Kotlin wrapper does not add a decorator-like API.

var registry = new TaskRegistry(db);
var task = registry.register(
"send-email", "tasks", call -> "{\"sent\":true}"
);
var result = task.enqueue("[\"alice@example.com\"]", "{}");
try (var worker = db.runTasks(registry)) {
var value = result.waitFor(WaitOptions.timeout(Duration.ofSeconds(10)));
}

Kotlin adds db.taskRegistry(), registerJson, enqueueJson, and suspending TaskResult.await helpers over the same runtime. See Function tasks for both examples and the shared queue-envelope format.

try (var db = Honker.open("app.db")) {
var outbox = db.outbox("email", payloadJson -> sendEmail(payloadJson));
db.transactionVoid(tx -> {
tx.execute(
"INSERT INTO orders (id, total) VALUES (?, ?)",
java.util.List.of(42, 9900)
);
outbox.enqueue(tx, "{\"order_id\":42}");
});
try (var worker = outbox.runWorker("email-worker")) {
Thread.currentThread().join();
}
}

Outbox jobs retry with exponential backoff when delivery throws.

For JDBC, Hibernate/JPA, jOOQ, or Exposed, let the ORM own its transaction and call honker_enqueue, notify, or stream SQL on the same connection before commit. Run workers in a separate Java/Kotlin process with the Honker runtime against the same .db file.

See the full Java and Kotlin ORM recipe for JDBC extension loading, Hibernate Session#doWork, jOOQ transactions, and Exposed examples.

Use temporary file-backed databases and real JVM subprocess workers for watcher backend tests. That proves bundled native loading, SQLite reopen behavior, cross-process wake delivery, SHM reopen behavior, and explicit experimental backend failures in the same shape production uses.