Skip to main content

Java SDK integrations

DVARA is an AI governance platform with an OpenAI-compatible data plane. The official OpenAI Java SDK, Spring AI, and LangChain4j all accept a custom base URL, so adding governance to an existing Java service is a single config change. Examples assume DVARA is running at http://localhost:8080 and you've created a tenant + API key via the Quickstart.

OpenAI Java SDK

The official OpenAI Java SDK exposes a .baseUrl() builder — same contract as the Python and JavaScript SDKs.

Maven dependency:

<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>0.31.0</version>
</dependency>

Basic chat:

import com.openai.client.OpenAIClient;
import com.openai.client.okhttp.OpenAIOkHttpClient;
import com.openai.models.ChatModel;
import com.openai.models.chat.completions.ChatCompletion;
import com.openai.models.chat.completions.ChatCompletionCreateParams;

OpenAIClient client = OpenAIOkHttpClient.builder()
.baseUrl("http://localhost:8080/v1")
.apiKey("your-dvara-api-key")
.build();

ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model(ChatModel.GPT_4O)
.addUserMessage("Explain microservices in one paragraph.")
.build();

ChatCompletion completion = client.chat().completions().create(params);
completion.choices().forEach(c -> System.out.println(c.message().content().orElse("")));

Streaming:

import com.openai.core.http.StreamResponse;
import com.openai.models.chat.completions.ChatCompletionChunk;

try (StreamResponse<ChatCompletionChunk> stream =
client.chat().completions().createStreaming(
ChatCompletionCreateParams.builder()
.model(ChatModel.GPT_4O)
.addUserMessage("Write a haiku about Java.")
.build())) {
stream.stream()
.flatMap(chunk -> chunk.choices().stream())
.flatMap(choice -> choice.delta().content().stream())
.forEach(System.out::print);
}

Structured output (JSON schema):

import com.openai.core.JsonValue;
import com.openai.models.ResponseFormatJsonSchema;

ChatCompletionCreateParams params = ChatCompletionCreateParams.builder()
.model(ChatModel.GPT_4O)
.addUserMessage("List 3 planets with their diameter in km.")
.responseFormat(ResponseFormatJsonSchema.builder()
.jsonSchema(ResponseFormatJsonSchema.JsonSchema.builder()
.name("planets")
.strict(true)
.schema(JsonValue.from(Map.of(
"type", "object",
"properties", Map.of(
"planets", Map.of(
"type", "array",
"items", Map.of(
"type", "object",
"properties", Map.of(
"name", Map.of("type", "string"),
"diameter_km", Map.of("type", "integer")),
"required", List.of("name", "diameter_km"))))
, "required", List.of("planets"))))
.build())
.build())
.build();

ChatCompletion completion = client.chat().completions().create(params);

Using Claude / Gemini via DVARA (same SDK):

// No SDK change — DVARA translates to the upstream provider based on the model name.
ChatCompletionCreateParams claudeParams = ChatCompletionCreateParams.builder()
.model("claude-sonnet-4-20250514")
.addUserMessage("Hello from the OpenAI Java SDK via DVARA!")
.build();
ChatCompletion claudeResponse = client.chat().completions().create(claudeParams);

ChatCompletionCreateParams geminiParams = ChatCompletionCreateParams.builder()
.model("gemini-2.0-flash")
.addUserMessage("Hello from Gemini via DVARA!")
.build();
ChatCompletion geminiResponse = client.chat().completions().create(geminiParams);

Environment variable approach:

export OPENAI_BASE_URL="http://localhost:8080/v1"
export OPENAI_API_KEY="your-dvara-api-key"
// fromEnv() reads OPENAI_BASE_URL and OPENAI_API_KEY.
OpenAIClient client = OpenAIOkHttpClient.fromEnv();

LangChain4j

Maven dependency:

<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
<version>1.0.0-beta1</version>
</dependency>

Basic chat:

import dev.langchain4j.model.openai.OpenAiChatModel;

OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("http://localhost:8080/v1")
.apiKey("your-dvara-api-key")
.modelName("gpt-4o")
.build();

String response = model.chat("What is the capital of Germany?");
System.out.println(response);

Streaming:

import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;

OpenAiStreamingChatModel model = OpenAiStreamingChatModel.builder()
.baseUrl("http://localhost:8080/v1")
.apiKey("your-dvara-api-key")
.modelName("gpt-4o")
.build();

model.chat("Write a haiku about Java.", new StreamingChatResponseHandler() {
@Override
public void onPartialResponse(String partialResponse) {
System.out.print(partialResponse);
}

@Override
public void onCompleteResponse(String completeResponse) {
System.out.println("\n--- Done ---");
}

@Override
public void onError(Throwable error) {
error.printStackTrace();
}
});

With AI Services (structured output):

import dev.langchain4j.service.AiServices;

interface MovieExpert {
@dev.langchain4j.service.UserMessage("Review the movie: {{movie}}")
MovieReview review(@dev.langchain4j.service.V("movie") String movie);
}

record MovieReview(String title, double rating, String summary) {}

OpenAiChatModel model = OpenAiChatModel.builder()
.baseUrl("http://localhost:8080/v1")
.apiKey("your-dvara-api-key")
.modelName("gpt-4o")
.responseFormat("json")
.build();

MovieExpert expert = AiServices.create(MovieExpert.class, model);
MovieReview review = expert.review("Inception");
System.out.printf("%s: %.1f/10 - %s%n", review.title(), review.rating(), review.summary());

Using Claude via DVARA:

OpenAiChatModel claude = OpenAiChatModel.builder()
.baseUrl("http://localhost:8080/v1")
.apiKey("your-dvara-api-key")
.modelName("claude-sonnet-4-20250514")
.build();

String response = claude.chat("Hello from LangChain4j via DVARA!");

Spring AI

Spring AI has native OpenAI support with a configurable base URL.

Maven dependency:

<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-openai-spring-boot-starter</artifactId>
</dependency>

application.yml:

spring:
ai:
openai:
base-url: http://localhost:8080/v1
api-key: ${DVARA_API_KEY:your-dvara-api-key}
chat:
options:
model: gpt-4o
temperature: 0.7

Service class:

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

@Service
public class ChatService {

private final ChatClient chatClient;

public ChatService(ChatClient.Builder builder) {
this.chatClient = builder.build();
}

public String chat(String message) {
return chatClient.prompt()
.user(message)
.call()
.content();
}

// Streaming
public Flux<String> streamChat(String message) {
return chatClient.prompt()
.user(message)
.stream()
.content();
}
}

Structured output:

record CityInfo(String name, String country, int population, List<String> landmarks) {}

CityInfo city = chatClient.prompt()
.user("Tell me about Paris")
.call()
.entity(CityInfo.class);

System.out.printf("%s, %s — pop: %,d%n", city.name(), city.country(), city.population());

Switch models at runtime:

// Use GPT-4o
String gptResponse = chatClient.prompt()
.user("Hello!")
.options(OpenAiChatOptions.builder().model("gpt-4o").build())
.call()
.content();

// Use Claude — same client, different model
String claudeResponse = chatClient.prompt()
.user("Hello!")
.options(OpenAiChatOptions.builder().model("claude-sonnet-4-20250514").build())
.call()
.content();

Function calling:

@Bean
@Description("Get the current weather for a location")
public Function<WeatherRequest, WeatherResponse> getWeather() {
return request -> new WeatherResponse(request.city(), 22.5, "Sunny");
}

record WeatherRequest(String city) {}
record WeatherResponse(String city, double temperature, String condition) {}

String response = chatClient.prompt()
.user("What's the weather in Tokyo?")
.functions("getWeather")
.call()
.content();

Next steps