Installation
The Java bindings require JDK 22 or newer. They use the FFM (Foreign Function & Memory) API to call the native Rust engine. On JDK 24+, add
--enable-native-access=ALL-UNNAMED to your JVM options to silence native-access warnings. On versions 2.0.1 and earlier, the bundled native library must be provided manually: extract it from the jar for your platform and pass -Duniffi.component.zen_uniffi.libraryOverride=/absolute/path/to/library; newer versions extract it automatically.Basic usage
Loader
TheZenEngine constructor takes a ZenLoader that resolves decisions by key. ZenLoader is a sealed interface with four variants: Callback for loading from any storage backend, and the configurations Static, Filesystem, and Zip, which pre-load and pre-compile all decisions when you create the engine.
Loader configurations
Prefer a configuration when your decisions are known up front. The engine compiles them once, so evaluations skip loading and parsing entirely.Callback loader
UseZenLoader.Callback to load decisions from any storage backend. The callback returns CompletableFuture<JsonBuffer>; complete it with null when the decision does not exist. Use ConcurrentHashMap to cache decisions for optimal performance.
AWS S3
Azure Blob Storage
Google Cloud Storage
Async evaluation
Evaluation returnsCompletableFuture for non-blocking execution:
Batch evaluation
UseevaluateBatch to evaluate many contexts in a single call. Each request pairs a decision key with a context, and each result reports its own success or error:
Error handling
Tracing
Enable tracing to inspect decision execution:Expression utilities
Evaluate ZEN expressions outside of a decision context:Runtime requirements
The Java bindings use the FFM (Foreign Function & Memory) API from
java.lang.foreign for interoperability with the native Rust engine. FFM requires JDK 22 or newer.Best practices
Use try-with-resources.ZenEngine implements AutoCloseable to release native resources.
ZenEngine instance at application startup and reuse it for all evaluations.
Implement a loader for dynamic decisions. The loader pattern centralizes decision loading logic and enables caching with ConcurrentHashMap.
Use CompletableFuture composition. Chain async operations or use allOf for parallel evaluation of multiple decisions.