This document describes how to set up your development environment to build and test the Valkey GLIDE Java wrapper.
The Valkey GLIDE Java wrapper consists of both Java and Rust code. Rust bindings for the Java Native Interface are implemented using jni-rs, and the Java JAR is built using Gradle. The Java and Rust components communicate using the protobuf protocol.
Note: See the Troubleshooting section below for possible solutions to problems.
Software Dependencies
- git
- GCC
- pkg-config
- protoc (protobuf compiler) >= 26.1
- openssl
- openssl-dev
- rustup
- Java 11
Dependencies installation for Ubuntu
sudo apt update -y
sudo apt install -y openjdk-11-jdk git gcc pkg-config openssl libssl-dev unzip
# Install rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
# Check that the Rust compiler is installed
rustc --version
Continue with Install protobuf compiler below.
Dependencies installation for CentOS
sudo yum update -y
sudo yum install -y java-11-openjdk-devel git gcc pkgconfig openssl openssl-devel unzip
# Install rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
Continue with Install protobuf compiler below.
Dependencies installation for MacOS
brew update
brew install openjdk@11 git gcc pkgconfig protobuf openssl protobuf
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source "$HOME/.cargo/env"
Continue with Install protobuf compiler below.
Install protobuf compiler
To install protobuf for MacOS, run:
brew install protobuf
# Check that the protobuf compiler version 26.1 or higher is installed
protoc --version
For the remaining systems, do the following:
PB_REL="https://github.com/protocolbuffers/protobuf/releases"
curl -LO $PB_REL/download/v26.1/protoc-26.1-linux-x86_64.zip
unzip protoc-26.1-linux-x86_64.zip -d $HOME/.local
export PATH="$PATH:$HOME/.local/bin"
# Check that the protobuf compiler version 26.1 or higher is installed
protoc --version
Before starting this step, make sure you've installed all software dependencies.
-
Clone the repository:
git clone https://github.com/valkey-io/valkey-glide.git cd valkey-glide/java
-
Initialize git submodule:
git submodule update --init --recursive
-
Build the Java wrapper (Choose a build option from the following and run it from the
java
folder):- Enter the java directory:
cd java
- Build in debug mode:
./gradlew :client:buildAll
- Build in release mode:
./gradlew :client:buildAllRelease
Development on the Java wrapper may involve changes in either the Java or Rust code. Each language has distinct linter tests that must be passed before committing changes.
Firstly, install the Rust linter
# Run from the `java` folder
# Will only need to run once during the installation process
rustup component add clippy rustfmt
cargo clippy --all-features --all-targets -- -D warnings
cargo fmt --manifest-path ./Cargo.toml --all
Java: For Java, we use Spotless and SpotBugs.
-
Spotless
# Run from the `java` folder ./gradlew :spotlessCheck # run first to see if there are any linting changes to make ./gradlew :spotlessApply # to apply these changes
-
SpotBugs
To run SpotBugs and generate reports:
# Run from the `java` folder ./gradlew spotbugsMain
This command will generate HTML and XML reports in the
build/reports/spotbugs/
directory.To view the SpotBugs findings:
- Open the HTML report located at
build/reports/spotbugs/main/spotbugs.html
in a web browser. - If you are using IntellJ Idea - open
build/reports/spotbugs/main/spotbugs.xml
in SpotBugs plugin as it will provide better experience.
Ensure any new findings are addressed and fixed before committing and pushing your changes.
Note: The
spotbugs
task is currently configured to not fail the build on findings. - Open the HTML report located at
Some troubleshooting issues:
- If the build fails after following the installation instructions, the
gradle
daemon may need to be restarted (./gradlew --stop
) so that it recognizes changes to environment variables (e.g.$PATH
). If that doesn't work, you may need to restart your machine. In particular, this may solve the following problems:- Failed to find
cargo
afterrustup
. - No Protobuf compiler (protoc) found.
- Failed to find
- If build fails because of rust compiler fails, make sure submodules are updated using
git submodule update
. - If protobuf 26.0 or earlier is detected, upgrade to the latest protobuf release.
An example app (glide.examples.ExamplesApp
) is available under examples project. To run the ExamplesApp against a local build of valkey-glide client, you can publish your JAR to local Maven repository as a dependency.
To publish to local maven run (default version 255.255.255
):
# Run from the `examples/java` folder
./gradlew publishToMavenLocal
You can then add the valkey-glide dependency to examples project:
repositories {
mavenLocal()
}
dependencies {
// Update to use version defined in the previous step
implementation group: 'io.valkey', name: 'valkey-glide', version: '255.255.255'
}
Optionally: you can specify a snapshot release:
export GLIDE_RELEASE_VERSION=1.0.1-SNAPSHOT
./gradlew publishToMavenLocal
You can then add the valkey-glide dependency to examples/java/build.gradle with the version and classifier:
repositories {
mavenLocal()
}
dependencies {
// Update to use version defined in the previous step
implementation group: 'io.valkey', name: 'valkey-glide', version: '1.0.1-SNAPSHOT', classifier='osx-aarch_64'
}
To run all tests, use the following command:
./gradlew test
To run the unit tests, use the following command:
./gradlew :client:test
To run FFI tests between Java and Rust, use the following command:
./gradlew :client:testFfi
To run end-to-end tests, use the following command:
./gradlew :integTest:test
IT suite start the server for testing - standalone and cluster installation using cluster_manager
script.
By default, it starts servers without TLS; to activate TLS add -Dtls=true
to the command line:
./gradlew :integTest:test -Dtls=true
To run a single test, use the following command:
./gradlew :integTest:test --tests '*.functionLoad_and_functionList' --rerun
To run one class, use the following command:
./gradlew :client:test --tests 'TransactionTests' --rerun
To run IT tests against an existing cluster and/or standalone endpoint, use:
./gradlew :integTest:test -Dcluster-endpoints=localhost:7000 -Dstandalone-endpoints=localhost:6379
If those endpoints use TLS, add -Dtls=true
(applied to both endpoints):
./gradlew :integTest:test -Dcluster-endpoints=localhost:7000 -Dstandalone-endpoints=localhost:6379 -Dtls=true
You can combine this with test filter as well:
./gradlew :integTest:test -Dcluster-endpoints=localhost:7000 -Dstandalone-endpoints=localhost:6379 --tests 'TransactionTests' -Dtls=true
To run server modules test (it doesn't start servers):
./gradlew :integTest:modulesTest -Dcluster-endpoints=localhost:7000 -Dtls=true
To (re)generate protobuf code, use the following command:
./gradlew protobuf
After pulling new changes, ensure that you update the submodules by running the following command:
git submodule update
A Valkey command can either have a standalone or cluster implementation which is dependent on their specifications.
- A node is an instance of a Valkey server, and a valkey cluster is composed of multiple nodes working in tandem.
- A cluster command will require a note to indicate a node will follow a specific routing. Refer to https://valkey.io/docs/topics/cluster-spec for more details on how hash slots work for cluster commands.
When you start implementing a new command, check the command_request.proto and request_type.rs files to see whether the command has already been implemented in another language such as Python or Node.js.
Standalone and cluster clients both extend BaseClient.java and implement methods from the interfaces listed in java/client/src/main/java/glide/api/commands
.
The return types of these methods are in the form of a CompletableFuture
, which fulfill the purpose of the asynchronous features of the program.
When implementing a command, include both a unit test and an integration test.
Implement unit tests in the following files:
- GlideClientTest.java for standalone commands.
- GlideClusterClientTest.java for cluster commands. These files are found in the java/client/src/test/java/glide/api path.
Implement integration tests in the following files:
- TransactionTests.java (standalone and cluster).
- TransactionTestsUtilities.java (standalone and cluster).
- SharedCommandTests.java (standalone and cluster).
- cluster/CommandTests.java (cluster).
- standalone/CommandTests.java (standalone). For commands that have options, create a separate file for the optional values.
BaseTransaction.java will add the command to the Transactions API. Refer to this link to view the interface directory. Refer to https://valkey.io/docs/topics/transactions/ for more details about how Transactions work in Valkey.
BaseTransaction.java and the methods within the command interfaces will both contain documentation on how the command operates. In the command interface each command's javadoc should contain:
- Detail on when Valkey started supporting the command (if it wasn't initially implemented in 6.0.0 or before).
- A link to the Valkey documentation.
- Information about the function parameters.
- Any glide-core implementation details, such as how glide-core manages default routing for the command. Reference this link for an example.
- The command's return type. In the BaseTransaction.java file, include "Command Response" before specifying the return type.
Refer to closed-PRs to see commands that have been previously merged.
Javac will create the name of the signature in Rust convention which can be called on native code.
- In the command line write:
javac -h . GlideValueResolver.java
The results can be found in the glide_ffi_resolvers_GlideValueResolver
file once the javac -h. GlideValueResolver.java
command is ran.
In this project, only the function name and signature name is necessary. lib.rs method names explicitly point to the native functions defined there.
- The module-info.java (glide.api) contains a list of all of the directories the user can access.
- Ensure to update the exports list if there are more directories the user will need to access.
- rust-analyzer - Rust language support for VSCode.
- spotless-gradle - Spotless Gradle plugin for VSCode.
- gradle - Gradle extension for Java.
- spotless-gradle - Spotless Gradle plugin for IntelliJ.
- lombok - Lombok plugin for IntelliJ.
- SpotBugs - SpotBugs plugin for IntelliJ.