Java SDK
For Java projects, two official SDKs are available:
- OpenAI compatible:
com.openai:openai-java(official) - Anthropic native:
com.anthropic:anthropic-java(official)
Examples are based on the official READMEs pulled via Context7. Check the upstream repos for the latest parameters and behavior: openai/openai-java, anthropics/anthropic-sdk-java.
Setup
export SAKRYLLE_API_KEY="sk-xxxxxxxxxxxxxxxx"JDK 8+ is required. Both SDKs use OkHttp as the HTTP client.
OpenAI compatible
Install
Maven:
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>1.0.0</version>
</dependency>Gradle (Kotlin DSL):
dependencies {
implementation("com.openai:openai-java:1.0.0")
}Look up the latest version on Maven Central: com.openai:openai-java. The version above is illustrative — defer to Maven Central in practice.
Minimal usage
openai-java reads the base URL and API key from environment variables:
export OPENAI_API_KEY="$SAKRYLLE_API_KEY"
export OPENAI_BASE_URL="https://api.sakrylle.com/v1"import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;
public class Demo {
public static void main(String[] args) {
// Reads OPENAI_API_KEY / OPENAI_BASE_URL automatically
OpenAIClient client = OpenAIOkHttpClient.fromEnv();
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("gpt-5.6-sol")
.addSystemMessage("You are a concise assistant.")
.addUserMessage("Explain vector databases in one sentence.")
.build();
ChatCompletion completion = client.chat().completions().create(params);
completion.choices().forEach(c -> System.out.println(c.message().content().orElse("")));
}
}If you prefer not to use environment variables, configure the builder explicitly:
OpenAIClient client = OpenAIOkHttpClient.builder()
.apiKey(System.getenv("SAKRYLLE_API_KEY"))
.baseUrl("https://api.sakrylle.com/v1")
.build();Streaming
createStreaming plus ChatCompletionAccumulator lets you assemble the final message:
import com.openai.helpers.ChatCompletionAccumulator;
ChatCompletionAccumulator acc = ChatCompletionAccumulator.create();
client.chat()
.completions()
.createStreaming(params)
.subscribe(chunk -> acc.accumulate(chunk).choices().stream()
.flatMap(choice -> choice.delta().content().stream())
.forEach(System.out::print))
.onCompleteFuture()
.join();
ChatCompletion finalCompletion = acc.chatCompletion();Tool calling
addTool(Class<T>) auto-generates JSON schema from a Java class:
import com.openai.core.JsonValue;
import com.openai.models.FunctionDefinition;
import com.openai.models.chat.completions.ChatCompletionTool;
ChatCompletionTool weatherTool = ChatCompletionTool.builder()
.function(FunctionDefinition.builder()
.name("get_weather")
.description("Look up the current weather for a city")
.parameters(JsonValue.from(Map.of(
"type", "object",
"properties", Map.of("city", Map.of("type", "string")),
"required", List.of("city"))))
.build())
.build();
ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model("gpt-5.6-sol")
.addTool(weatherTool)
.addUserMessage("What's the weather in Beijing today?")
.build();Anthropic native
Install
Maven:
<dependency>
<groupId>com.anthropic</groupId>
<artifactId>anthropic-java</artifactId>
<version>2.0.0</version>
</dependency>Gradle (Kotlin DSL):
dependencies {
implementation("com.anthropic:anthropic-java:2.0.0")
}Look up the latest version on Maven Central: com.anthropic:anthropic-java.
Minimal usage
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
public class Demo {
public static void main(String[] args) {
AnthropicClient client = AnthropicOkHttpClient.builder()
.apiKey(System.getenv("SAKRYLLE_API_KEY"))
.baseUrl("https://api.sakrylle.com")
.build();
MessageCreateParams params = MessageCreateParams.builder()
.model("claude-haiku-4-5-20251001")
.maxTokens(1024L)
.addUserMessage("Introduce Claude in one sentence.")
.build();
Message message = client.messages().create(params);
System.out.println(message.content());
}
}Use
https://api.sakrylle.comasbaseUrl; the SDK appends/v1/messagesautomatically.
Streaming
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.core.http.StreamResponse;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.RawMessageStreamEvent;
AnthropicClient client = AnthropicOkHttpClient.builder()
.apiKey(System.getenv("SAKRYLLE_API_KEY"))
.baseUrl("https://api.sakrylle.com")
.build();
MessageCreateParams params = MessageCreateParams.builder()
.model("claude-haiku-4-5-20251001")
.maxTokens(1024L)
.addUserMessage("Write a four-line poem.")
.build();
try (StreamResponse<RawMessageStreamEvent> stream = client.messages().createStreaming(params)) {
stream.stream()
.flatMap(event -> event.contentBlockDelta().stream())
.flatMap(delta -> delta.delta().text().stream())
.forEach(text -> System.out.print(text.text()));
}Error handling
com.openai.errors.* and com.anthropic.errors.* both subclass by HTTP status code:
import com.openai.errors.OpenAIException;
import com.openai.errors.AuthenticationException;
import com.openai.errors.RateLimitException;
try {
client.chat().completions().create(params);
} catch (AuthenticationException e) {
System.err.println("Key invalid or revoked");
} catch (RateLimitException e) {
System.err.println("Rate limited, retry later");
} catch (OpenAIException e) {
System.err.println("Upstream error: " + e.statusCode() + " " + e.getMessage());
}For a full error table, see Errors.
