Aerospike Java SDK

NOTE

This is a developer preview, not yet ready for production use, but with future releases planned. We encourage feedback from the Aerospike developer community through GitHub issues.

A ground-up redesign of the Aerospike Java client — fluent, type-safe, and built for modern Java (21+).

Quick Start

import com.aerospike.client.sdk.*;
import java.util.List;
import java.util.Map;

public class QuickStart {
    public static void main(String[] args) {
        // Connect to the cluster
        try (Cluster cluster = new ClusterDefinition("localhost", 3000)
                .withNativeCredentials("admin", "password")
                .connect()) {

            Session session = cluster.createSession(Behavior.DEFAULT);
            DataSet users = DataSet.of("test", "users");

            // --- Insert some data ---
            session.upsert(users.id("alice"))
                .bin("name").setTo("Alice")
                .bin("age").setTo(30)
                .bin("tags").setTo(List.of("admin", "active"))
                .bin("scores").setTo(List.of(95, 87, 92, 78))
                .bin("prefs").setTo(Map.of("theme", "dark", "lang", "en"))
                .execute();

            // --- Read it back ---
            Record record = session.query(users.id("alice"))
                .execute()
                .getFirstRecord();

            System.out.println(record.getString("name"));  // Alice
            System.out.println(record.getLong("age"));      // 30

            // --- Update a bin ---
            session.update(users.id("alice"))
                .bin("age").setTo(31)
                .execute();

            // --- Append to a list ---
            session.upsert(users.id("alice"))
                .bin("scores").listAppend(99)
                .execute();

            // --- Query a list range ---
            session.query(users.id("alice"))
                .bin("scores").onListValueRange(90, 100).getValues()
                .execute();

            // --- Set a map entry ---
            session.upsert(users.id("alice"))
                .bin("prefs").onMapKey("notifications").upsert(true)
                .execute();

            // --- Read a map key ---
            session.query(users.id("alice"))
                .bin("prefs").onMapKey("theme").getValues()
                .execute();

            // --- Filter with AEL ---
            session.query(users)
                .where("$.age > 25 and 'active' in $.tags")
                .execute();
        }
    }
}

What's happening

  1. Connect — ClusterDefinition configures the connection (hosts, credentials, TLS); calling .connect() returns a Cluster that manages node discovery and connection pooling. Cluster is Closeable — wrap it in try-with-resources.

  2. Session — A lightweight handle through which all operations flow. Create as many as you need with different Behavior profiles to vary timeouts, retries, and consistency settings without changing application code.

  3. Write verbs — upsert, insert, update, replace, and replaceIfExists each enforce intent at the method level. No more runtime policy flags.

  4. Reads — session.query(key) returns a RecordStream that works as an Iterator, a Java Stream, or a CompletableFuture.

  5. CDT operations — Bins containing Lists and Maps are manipulated through a fluent navigation chain: select elements (.onListValueRange(...), .onMapKey(...)), then choose an action (.getValues(), .remove(), .count()). See the List Operations and Map Operations references for every available operation.

  6. AEL filtering — The Aerospike Expression Language lets you write server-side filters as concise strings ("$.age > 25"). When a matching secondary index exists, the SDK selects it automatically. See the AEL Documentation for the full language reference.

Features

For comprehensive documentation with code examples for every feature, see the Key Features Guide.

FeatureDescriptionDetails
Fluent write verbsinsert, update, upsert, replace, replaceIfExists — intent is explicit at the method levelWrite Operations
Reads & RecordStreamUniversal RecordStream return type with Iterator, Stream, and CompletableFuture supportRead Operations, RecordStream
Heterogeneous batchingMix reads, writes, deletes, and UDFs across different keys in a single server round-tripBatch Chains
AEL (Expression Language)Text-based server-side filters with automatic secondary index selectionAEL Reference
Expression bin opsCompute derived values server-side (selectFrom, upsertFrom)Expression Ops
List & Map CDT operationsFluent navigation and manipulation of nested collection data typesList Ops, Map Ops
CDT path expressionsIterate, filter, collect, modify, or remove matching nested elements (onEachChild, removeMatches)Path ops
Async & reactiveexecuteAsync() with CompletableFuture and Flow.Publisher (backpressure)Async Operations
TransactionsMulti-record ACID transactions with automatic retry on transient failuresTransactions
Behavior (policy config)Cascading, selector-based configuration — separate dev concerns from ops concernsBehavior
Object mappingRecordMapper and TypedDataSet for mapping Java objects to/from recordsObject Mapping
Queries & scansDataset-level queries with pagination, sorting, partition targeting, and throttlingQueries
Background operationsServer-side bulk updates, deletes, and UDF execution across entire setsBackground Ops
UDFsRegister, execute, and chain Lua User Defined FunctionsUDFs
Secondary indexesCreate and drop indexes; AEL queries use them automaticallyIndexes
Info commandsTyped, structured access to cluster metadata (namespaces, sets, indexes)Info Commands
Exception hierarchyFine-grained unchecked exceptions with result codes for programmatic handlingExceptions

Known traps

  • Do not special-case a batch of one key. A node sub-batch of size 1 already uses the single-record path. Application-level if (n == 1) branching is redundant; generated code has been observed reimplementing this optimization. See Heterogeneous Batch Chains.
  • Do not loop single-key calls to emulate a batch. Pass users.ids(...) (or a List<Key>) to session.query, session.exists, or a write verb. The SDK uses the same verb for one key and many; looping session.query(users.id(x)) issues sequential point calls.
  • Path-expression removal is onEachChild(…).removeMatches(), not a missing API. Do not build CdtOperation.modifyByPath with Exp.removeResult(), and do not use .remove() after onEachChild — .remove() is the single-selection terminal. Server 8.1.1+. See CDT path operations.

Building

mvn compile        # Compile
mvn test           # Run tests
mvn javadoc:javadoc  # Generate Javadoc

Requirements

  • Java 21+ (Java 24+ recommended for improved virtual thread performance)
  • Maven 3.9.5+