Docs
View as markdown

Java API

The com.relate classes and their methods, the Cypher and Java value mapping in both directions, the exception classes and codes, and native loading.

java

The Java client A language package that runs the relate engine inside a program's process: the Python, Node.js, Rust, Java, Go and Swift clients. Read more in the glossary is the artifact com.relate:relate, package com.relate, for Java 17 or later. It calls the relate C library, librelate_ffi, through JNA (Java Native Access), and its jar carries that library; the library's C application binary interface (C ABI) is version 2. Its two dependencies are JNA and Jackson databind. Every call is synchronous, and every failure is an unchecked exception. This page describes the client of relate 0.1.2.

Synopsis

package com.relate;

public class Database implements AutoCloseable {
    public static Database open(String uri);
    public static Database openReadOnly(String uri);
    public Connection connect();
    public synchronized Connection connect(String namespace);
    public synchronized void checkpoint();
    public synchronized void close();

    public static class Connection implements AutoCloseable {
        public Result query(String cypher);
        public synchronized Result query(String cypher, Map<String, ?> params);
        public synchronized void setNamespace(String namespace);
        public synchronized void begin();
        public synchronized String commit();
        public synchronized void rollback();
        public synchronized void close();
    }

    public static class Result {
        public List<String> columns();
        public List<List<Object>> rows();
        public QueryType getQueryType();
        public Namespace getNamespace();
        public String getBookmark();
        public List<Notification> getNotifications();
        public PlanDocument getPlan();
    }
}

Public types

TypeKindHolds
Databaseclass, AutoCloseableAn open store
Database.Connectionstatic nested class, AutoCloseableOne session on a store
Database.Resultstatic nested classOne statement's columns, rows, and metadata
NoderecordelementId, id, labels, properties
RelationshiprecordelementId, id, startElementId, startId, endElementId, endId, type, properties
Pathrecordelements: node, relationship, …, node
Pointrecordsrid, x, y, z (null on a 2D point)
DurationValuerecordmonths, days, seconds, nanos
VectorValuerecorddtype, coordinates
QueryTypeenumREAD, WRITE, READ_WRITE, SCHEMA
NamespaceenumNEO4J, SYSTEM, SYSTEM_ONTOLOGIES
Notificationfinal classOne planner notification
Severity, CategoryenumsA notification's severity and category
PlanDocument, PlanNode, PlanActual, PlanStart, PlanFrontier, PlanKernelclasses with public fieldsThe structured plan
RelateExceptionRuntimeExceptionThe base of every client exception
TransientException, ClientException, DatabaseExceptionsubclasses of RelateExceptionThe engine's classification of a failure
RelateException.StageenumCOMPILE, RUNTIME, INTERNAL

Database

MethodReturnsBehavior
open(String uri)DatabaseOpens :memory:, a directory store or a .rl store for writing; creates a missing store
openReadOnly(String uri)DatabaseLoads an existing store once; refuses writes and checkpoints; a missing store is an error
connect()ConnectionA connection in the neo4j namespace
connect(String namespace)ConnectionA connection in neo4j, system or system_ontologies, matched case-insensitively; null selects neo4j
checkpoint()voidWrites a checkpoint, folding the write-ahead log into a fresh snapshot of committed state; refused on a read-only database
close()voidCloses the store; idempotent; required before the same file store opens again in this Java virtual machine (JVM)

A failed open or openReadOnly throws DatabaseException with message internal error, code Neo.DatabaseError.General.UnknownError, GQLSTATUS 42000 and stage INTERNAL, whether the store is locked by another writer or missing. An unknown namespace throws ClientException: semantic error: DatabaseNotFound: Graph not found: <name>.

Connection

Database.Connection, a static nested class, has these methods:

MethodReturnsBehavior
query(String cypher)ResultRuns one statement with no parameters; auto-commits outside an explicit transaction
query(String cypher, Map<String, ?> params)ResultRuns one statement with named parameters; a null map binds none
setNamespace(String namespace)voidChanges the session namespace; refused inside a transaction
begin()voidOpens an explicit transaction; transactions do not nest
commit()StringCommits; returns the bookmark "relate:<n>", or null when the transaction wrote nothing
rollback()voidDiscards the explicit transaction
close()voidDisconnects; idempotent

Every method is synchronized: a connection serves one call at a time, and concurrent callers wait. A connection's own refusals, each a ClientException with code Neo.ClientError.Statement.SemanticError and GQLSTATUS 42000:

CallMessage
begin() inside a transactionsemantic error: already in a transaction
commit() or rollback() with no transactionsemantic error: no transaction
setNamespace(…) inside a transactionsemantic error: TransactionError: Cannot change the namespace while a transaction is open.

A failed commit() ends the transaction. A call on a closed connection or database throws RelateException with message connection is closed or database is closed and a null code.

Result

Database.Result, a static nested class, holds every row, copied out of the engine before query returns.

MethodReturns
columns()The column names, in RETURN order
rows()One List<Object> per row, cells in column order, typed as in Values
getQueryType()A QueryType: READ, WRITE (a write with no columns), READ_WRITE (a write with columns) or SCHEMA; EXPLAIN and PROFILE report the wrapped statement's type
getNamespace()A Namespace: NEO4J, SYSTEM or SYSTEM_ONTOLOGIES; the statement's USE target, else the session namespace
getBookmark()An auto-commit write's bookmark, relate:<n>; null for a read, an EXPLAIN, a write whose counters are all zero (it changed nothing), and any statement inside an explicit transaction
getNotifications()The statement's notifications; filled by EXPLAIN and PROFILE, empty on a plain run
getPlan()The relate.plan/v1 plan document under EXPLAIN or PROFILE; null on a plain run

QueryType, Namespace, Severity and Category each have wire(), the string the C ABI carries: QueryType.READ_WRITE.wire() is "rw", Namespace.NEO4J.wire() is "neo4j", and a Severity or Category constant's string is its name. A Result carries no mutation counters, column types, or timings. A bookmark's <n> grows across every connection of the store and orders as a number: as strings, "relate:10" sorts before "relate:9".

Values

Each result cell is decoded into one Java type per Cypher kind:

Cypher kindJava type
NULLnull
BOOLEANBoolean
INTEGERLong, any 64-bit value
FLOATDouble, NaN and infinities included
STRINGString, interior NUL characters kept
LISTList<Object>
MAPMap<String, Object>, in engine order
nodeNode
relationshipRelationship
pathPath, its elements alternating Node and Relationship
POINTPoint; srid 7203 or 4326 in 2D, 9157 or 4979 in 3D
DATE, LOCAL TIME, LOCAL DATETIMELocalDate, LocalTime, LocalDateTime
ZONED TIMEOffsetTime; a time keeps an offset, never a zone id
ZONED DATETIMEZonedDateTime when the value has a zone id, OffsetDateTime when it has only an offset
DURATIONDurationValue; duration('P1Y2M') has months 14
VECTORVectorValue; coordinates holds Long for the INTEGER* types and Double for the FLOAT* types
byte arrayList<Long>, each 0 to 255

An element id The string elementId() returns for a node or relationship, such as 4:relate-neo4j:n0; it stays the same when the store is closed and opened again. Read more in the glossary is the string elementId() returns, such as 4:relate-neo4j:n0, so it round-trips through a parameter. The long ids are the deprecated numeric ids id() returns. A map key holding a NUL character, or a value kind the client does not know, throws RelateException instead of returning a value.

Parameters

query(cypher, params) binds each map entry as one Cypher value, with no JSON in between:

Java typeBinds as
nullNULL
BooleanBOOLEAN
Byte, Short, Integer, LongINTEGER
Float, DoubleFLOAT
StringSTRING
LocalDate, LocalTime, LocalDateTimeDATE, LOCAL TIME, LOCAL DATETIME
OffsetTimeZONED TIME
OffsetDateTime, ZonedDateTimeZONED DATETIME; a ZonedDateTime keeps its zone id, one zoned at a ZoneOffset crosses as the offset form
DurationValueDURATION
java.time.DurationDURATION with zero months and days
PointPOINT
VectorValueVECTOR; dtype is one of INTEGER8, INTEGER16, INTEGER32, INTEGER, FLOAT16, BFLOAT16, FLOAT32, FLOAT; coordinates must be Long for the INTEGER* dtypes and Double for the FLOAT* dtypes
ListLIST, in order
MapMAP, nested to any depth; keys must be String

Any other type throws IllegalArgumentException before the statement runs, such as cannot bind parameter "x": unsupported Java type java.lang.Object. So do a vector coordinate of the wrong box type, as in cannot bind vector parameter with dtype INTEGER8: coordinate 0 is java.lang.Integer, expected Long, and a map key that is not a String, as in cannot bind nested map parameter "m": key 1 is java.lang.Integer, expected String. A value the engine refuses, such as an impossible date or an unknown zone, throws RelateException with stage INTERNAL. A statement that refers to a parameter the map lacks fails with semantic error: ParameterMissing: Expected parameter(s): <names>.

Errors

ClassThrown whenisRetryable()
TransientExceptionThe engine marks the failure retryable: a write-write conflict, Neo.TransientError.Transaction.Outdated, message write-write conflict, or the retryable workspace captrue
ClientExceptionThe code starts Neo.ClientError.: syntax, types, a missing parameter, an unknown namespace, a write on a read-only storefalse
DatabaseExceptionThe code starts Neo.DatabaseError.: engine failures, a failed open, and the C boundary's INTERNAL stagefalse
RelateExceptionAny other code, and the client's own failures: native loading, a closed handle, a malformed C ABI payload, such as a query type, namespace, notification severity, or category outside its enumfalse

Every class has these getters:

GetterReturns
getMessage()The engine's message
getCode()The Neo4j status code, such as Neo.ClientError.Statement.ArithmeticError; null on a client-side failure
getGqlStatus()The five-character GQLSTATUS, such as 22G03; null on a client-side failure
getStage()COMPILE (parse or plan), RUNTIME (execution) or INTERNAL (the C boundary: a poisoned handle, a caught panic, an undecodable argument); null on a client-side failure
isRetryable()true exactly when running the same work again can succeed

A conflict surfaces on an auto-commit statement or on commit(). After an INTERNAL failure the handle may be poisoned; close() still works on it. A write on a read-only database throws ClientException with code Neo.ClientError.Statement.SemanticError and GQLSTATUS 42N18. The errors reference lists the engine's messages.

Notifications and plans

Notification has the getters getCode(), getGqlStatus(), getSeverity() (a Severity: INFORMATION or WARNING), getCategory() (a Category: PERFORMANCE, UNRECOGNIZED, DEPRECATION, SCHEMA or HINT), getTitle(), getDescription(), getRemedy() and getOperatorId(), a Long that is null on a statement-scoped notification. The list follows plan pre-order, then statement-scoped entries.

The plan classes have public fields:

ClassFields
PlanDocumentschema (relate.plan/v1), profiled, statement, root
PlanNodeoperator, details, identifiers, estimatedRows, actual, children, warnings (the operator's notifications)
PlanActualrows, timeMs, totalTimeMs (the operator's time plus its descendants'), dbHits, seekMs, walkMs, loops (a Long, null on an operator with no input clause), memoryBytes, expressionBuiltBytes, hops, neighborWalks, nodeReads, batched, zoneSkips, frontier, frontierDecline (null when the frontier never declined), start, kernel (null when no kernel served the walk); the whole object is null on an EXPLAIN plan
PlanStartelement, backward, reason
PlanFrontieredgeVisits, levels, endpoints, cells, memoHits, memoMisses, representativeProofs, searchProven, searchDisproven, declinedExhausted, budgetFraction; all zeros when the operator walks no frontier
PlanKernelrung: chain, hub-star, frontier-nfa or walker; hops, a Long that only chain sets

Native library

The first use of Database in a JVM resolves the library once, in this order:

StepSource
1RELATE_LIB, when set and not empty: a path to a library, for development
2The jar's resource native/<key>/<library> for the running platform, extracted to the cache and loaded by absolute path
3Neither: the first call throws RelateException beginning relate: no bundled native library for platform <key>

The system library path, java.library.path and jna.library.path are never searched. The platforms:

os.name, os.archKeyLibraryClassifier
Mac OS X, aarch64darwin-arm64librelate_ffi.dylibosx-aarch_64
Mac OS X, x86_64darwin-x64librelate_ffi.dylibosx-x86_64
Linux, aarch64linux-arm64librelate_ffi.solinux-aarch_64
Linux, amd64linux-x64librelate_ffi.solinux-x86_64
Windows*, amd64win32-x64relate_ffi.dllwindows-x86_64

arm64 and x86_64 are accepted spellings of the same architectures. Any other platform throws RelateException beginning relate: unsupported platform os.name=. The plain jar carries all five libraries; each classifier jar carries one.

SettingDefaultEffect
-Drelate.native.cache=<dir>macOS ~/Library/Caches/relate/native; Linux $XDG_CACHE_HOME/relate/native or ~/.cache/relate/native; Windows %LOCALAPPDATA%\relate\nativeThe cache root; the library lands in <root>/<version>/<key>-<first 16 hex digits of its SHA-256>/
RELATE_LIBunsetA library path that replaces the jar's
--enable-native-access=ALL-UNNAMEDoffOn Java 24 or later, silences the JVM's restricted-method warning when JNA loads

The extraction writes a temporary file and renames it into place, so concurrent JVMs never load a partial file. Old versions' directories stay until removed. A library of another C ABI version throws RelateException beginning incompatible librelate_ffi at <path>. Every jar also carries the skill file .agents/skills/relate/SKILL.md.

Limits

The limits come from the engine and are the same on every surface: a statement's text is at most 4194304 bytes (syntax error: query text of <n> bytes exceeds the maximum query size of 4194304 bytes), one value a statement builds is bounded by the expression memory cap, and a file-backed store has one writing open across every process. Limits and sizing lists each limit with its default and the setting that changes it.

Capabilities

FeatureJava
In-memory storeA store that lives only in the process.yesDatabase.open(":memory:")
Directory storeA store in a directory on disk.yesDatabase.open(path)
Single-file .rl storeA store in one .rl file.yesDatabase.open("graph.rl")
Read-only openAn open that loads the store once and refuses every write.yesDatabase.openReadOnly(uri)
Explicit transactionsSeveral statements committed or rolled back together.yesbegin(), commit(), rollback()
Parameters$name values passed beside the statement.yesquery(statement, Map)
Column types, counters and timingsMetadata returned with each result.partialquery type (a typed QueryType), namespace, bookmark, notifications and plan; no column types, counters or timings
NotificationsThe engine's query notifications (for example a Cartesian product), each with a remedy.yesgetNotifications()
Arrow outputResults as Apache Arrow.nono Arrow call in the client
Change data captureReading committed changes from a slot.nono change-data-capture call in the client
Full-text searchFull-text indexes and their queries.yesCREATE FULLTEXT INDEX and full-text SEARCH through the C ABI
LOAD CSV from local filesLocal LOAD CSV under a configured directory (denied unless one is set).yesRELATE_LOAD_CSV_DIR, read by the C ABI's open
Load a store from a URLOpening a .rl store fetched over https.nono open from a URL in the client
Agent modeThe CLI's agent defaults: the 100-row cap and the piped toon output.noA CLI setting

Each cell is yes, no, partial or unknown, with the call, flag or reason. Checked on 2026-11-09 against relate 0.1.2: runs of the CLI binary and relate serve (Bolt, HTTP and MCP), the WebAssembly build this site ships, and the Python, Node.js, C, Java, Go, Swift and Rust clients, and each surface's upstream reference. The C, Java, Go and Swift clients load the same C ABI library as the Node.js client.

Example

This program writes two Person nodes and a KNOWS relationship to an in-memory store and prints the Java type of each returned value:

import com.relate.Database;

public class Values {
    public static void main(String[] args) {
        try (Database db = Database.open(":memory:");
             Database.Connection conn = db.connect()) {
            var result = conn.query("""
                CREATE (ada:Person {name: 'Ada'})-[k:KNOWS {since: 2024}]->(grace:Person {name: 'Grace'})
                RETURN ada, k, 9007199254740993 AS big, 1.5 AS ratio, date('2024-05-06') AS day,
                       datetime('2024-05-06T09:30:00[Europe/Berlin]') AS meeting, duration('P1Y2M') AS term,
                       point({x: 1, y: 2}) AS spot, vector([1, 2, 3], 3, INT8) AS counts""");
            for (int i = 0; i < result.columns().size(); i++) {
                Object value = result.rows().get(0).get(i);
                System.out.println(result.columns().get(i) + ": " + value.getClass().getSimpleName() + " " + value);
            }
        }
    }
}
ada: Node Node[elementId=4:relate-neo4j:n0, id=0, labels=[Person], properties={name=Ada}]
k: Relationship Relationship[elementId=5:relate-neo4j:r0, id=0, startElementId=4:relate-neo4j:n0, startId=0, endElementId=4:relate-neo4j:n1, endId=1, type=KNOWS, properties={since=2024}]
big: Long 9007199254740993
ratio: Double 1.5
day: LocalDate 2024-05-06
meeting: ZonedDateTime 2024-05-06T09:30+02:00[Europe/Berlin]
term: DurationValue DurationValue[months=14, days=0, seconds=0, nanos=0]
spot: Point Point[srid=7203, x=1.0, y=2.0, z=null]
counts: VectorValue VectorValue[dtype=INTEGER8, coordinates=[1, 2, 3]]

See also