Welcome to libsql-java. This repository implements a pure-Java JDBC driver, client library, and protocol codec for libSQL / sqld over the Hrana protocol.
This guide provides developers and automated AI agents with instructions on architecture, tooling, build conventions, and verification workflows.
- Java Version: Java LTS.
- Environment Management: Tooling is managed via mise (
mise.toml). - Build System: Maven with the included wrapper (
./mvnw). - Container Runtime: Docker or Podman (with socket exposed) for Testcontainers.
# Ensure correct Java LTS environment
mise install
# Verify Java & Maven
mise exec -- java -version
mise exec -- ./mvnw -versionlibsql-java/
├── libsql-hrana-codec/ # Core protocol data structures & DirectHranaJsonCodec
├── libsql-client/ # Low-level HTTP transport, baton state management, pipeline queue
├── libsql-jdbc/ # Standard JDBC 4.3 driver (java.sql.* implementation)
├── libsql-itests/ # Testcontainers (sqld) and Toxiproxy integration tests
├── libsql-conformance/ # Selected xerial/sqlite-jdbc tests running against libSQL
├── tools/ # Maintainer scripts such as export-upstream
├── upstream-xerial_sqlite-jdbc/ # Vendored xerial/sqlite-jdbc sources for conformance tests
└── vendor/ # Upstream specifications and documentation (Hrana v3, sqld)
-
libsql-hrana-codec:- Zero external runtime dependencies.
DirectHranaJsonCodechandles streaming JSON encoding/decoding directly for maximum performance.- Preserves 64-bit integer precision and binary base64 encoding.
-
libsql-client:- Built on
java.net.http.HttpClientwith pooled connection reuse. - Manages baton lifecycle,
/v3/pipelineexecution, and stream close handshakes.
- Built on
-
libsql-jdbc:- Standards-compliant JDBC 4.3 implementation.
- Maps URL schemes:
jdbc:libsql:http://...,jdbc:libsql:https://..., andjdbc:sqlite:http://.... - Maps SQLite dynamic typing to JDBC SQL types and translates Hrana error codes to
SQLExceptionhierarchies.
-
libsql-itests:- All tests run against a pinned
sqldimage (ghcr.io/tursodatabase/libsql-server:v0.24.33). - The pin lives in the root
pom.xmlas thelibsql.imageproperty, and Maven passes it to both the integration and conformance test JVMs. Override it with-Dlibsql.image=...only for a deliberate version bump. - Includes HikariCP connection pool churn tests and Toxiproxy network toxicity tests.
- All tests run against a pinned
We enforce code hygiene using Spotless:
- Format check:
mise exec -- ./mvnw spotless:check - Apply format:
mise exec -- ./mvnw spotless:apply
CI will fail if files contain trailing whitespace, missing newline terminations, or formatting violations. Run spotless:apply before submitting changes.
mise exec -- ./mvnw testRequires a running Docker or Podman daemon:
mise exec -- ./mvnw clean verifyTo run a specific test:
mise exec -- ./mvnw -pl libsql-itests -Dtest=HikariCpIntegrationIT testUnder nono, set DOCKER_CONFIG before the command, as described in the workaround below.
This environment may run inside a nono filesystem sandbox. The sandbox can block reads of ~/.docker/config.json even when docker info works. Testcontainers then fails with:
ServiceConfigurationError: ... EnvironmentAndSystemPropertyClientProviderStrategy could not be instantiated
Caused by: java.io.FileNotFoundException: /home/<user>/.docker/config.json (Permission denied)
Check the exact path with:
nono why --self --path ~/.docker/config.json --op readDo not change file permissions or the nono profile from inside the sandbox.
The repository ships one shared readable Docker config at libsql-conformance/src/test/docker-config/config.json. It is an empty auth config, so it works only for public images such as the sqld and Toxiproxy images that the integration tests use. Both modules can use it.
libsql-conformance uses the config automatically. It copies src/test/docker-config/config.json to target/docker-config and sets DOCKER_CONFIG for the Failsafe fork. To use a readable copy of your real Docker config instead, override the module property:
./mvnw -pl libsql-conformance -am -Ddocker.config.dir=/path/to/docker-config verifySetting DOCKER_CONFIG in the shell is not enough for libsql-conformance, because its Failsafe fork receives its own value from docker.config.dir.
libsql-itests has no copy step. Point DOCKER_CONFIG at the shared config directory in the shell, and the Failsafe fork inherits it:
DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" \
./mvnw -pl libsql-itests -am verifyThe same override works for a single integration test:
DOCKER_CONFIG="$PWD/libsql-conformance/src/test/docker-config" \
./mvnw -pl libsql-itests -am -Dit.test=HikariCpIntegrationIT verifyUse the absolute path shown. A relative DOCKER_CONFIG is resolved against the fork's working directory, not the shell's.
JDBC 4.3 Appendix B is the oracle for type mapping. The source is vendor/JDBC4-TYPE-MAPPING.md.
- When Appendix B defines a conversion or mapping and sqlite-jdbc disagrees, Appendix B wins. A conformance test that encodes the xerial behavior is quarantined in
libsql-conformance, not copied. - Keep sqlite-jdbc parity only where Appendix B is silent. Parity never overrides a defined Appendix B conversion.
- Table B-6 is a required-support matrix, not a rejection list. A representable declared column is not rejected because of its declared type; the stored value decides the conversion, matching sqlite-jdbc. Reject a declared type only for the five N/A types. Unimplemented getters still throw for any column.
ARRAY,STRUCT,REF,JAVA_OBJECT, andDISTINCTare N/A. The driver throwsSQLFeatureNotSupportedExceptionand does not emulate them.- An expression column has no declared type. Its storage-class fallback is a documented exception in
docs/jdbc-appendix-b-compliance.md, not a supported Appendix B row.
The compliance profile is docs/jdbc-appendix-b-compliance.md. Run the commands in README.md before changing a type mapping.
- Clean Commits: Use Conventional Commits (e.g.
feat(jdbc): ...,fix(codec): ...,docs: ...). - No Proprietary Information: Never commit credentials, private tokens, internal corporate urls, or proprietary notices.
- Dependency Minimization: Keep runtime dependencies minimal. Client and codec modules should remain lightweight.
- Error Handling: Do not swallow exceptions. Map protocol or transport errors into appropriate
SQLExceptionorLibsqlExceptiontypes.