Skip to main content

Getting started

Your first program

This program builds an operator, writes a file, reads it back, inspects its metadata, and deletes it. It runs against the in-memory service with no credentials, so you can run it right after adding the dependency.

The operator holds a native resource, so close it when you are done — a try-with-resources block does this for you:

package org.apache.opendal.examples;

import java.util.HashMap;
import org.apache.opendal.Metadata;
import org.apache.opendal.Operator;

public class Main {
public static void main(String[] args) {
// Configure a service, then build an operator from it.
try (Operator op = Operator.of("memory", new HashMap<>())) {
// The same verbs work on every service.
op.write("hello.txt", "Hello, World!");

byte[] data = op.read("hello.txt");
System.out.println(new String(data));

Metadata meta = op.stat("hello.txt");
System.out.println("size = " + meta.getContentLength() + " bytes");

op.delete("hello.txt");
}
}
}

write accepts a String or byte[]; read returns byte[].

Point it at a real backend

Only the service changes; the operations stay identical. The first argument is the scheme, and configuration is a Map<String, String>:

import java.util.HashMap;
import java.util.Map;
import org.apache.opendal.Operator;

Map<String, String> conf = new HashMap<>();
conf.put("bucket", "my-bucket");
conf.put("region", "us-east-1");

try (Operator op = Operator.of("s3", conf)) {
op.write("hello.txt", "Hello from S3!");
System.out.println(new String(op.read("hello.txt")));
}

The native library bundles every service, so there is nothing extra to install. The next page, Connecting to your storage, covers typed config builders and credentials in depth; Services lists every backend and its keys.

Sync vs async

Operator runs every call synchronously. For non-blocking code, use AsyncOperator: it has the same verbs, but each returns a CompletableFuture:

import java.util.HashMap;
import java.util.Map;
import org.apache.opendal.AsyncOperator;

Map<String, String> conf = new HashMap<>();
conf.put("bucket", "my-bucket");
conf.put("region", "us-east-1");

try (AsyncOperator op = AsyncOperator.of("s3", conf)) {
op.write("hello.txt", "Hello, World!")
.thenCompose(v -> op.read("hello.txt"))
.thenAccept(data -> System.out.println(new String(data)))
.join();
}

Call op.blocking() on an AsyncOperator to get a synchronous Operator backed by the same configuration.