Java & Spring Boot
The Adjudon Java SDK is the integration path for Spring Boot
backends, the dominant stack at the DACH banks Adjudon was built
to serve. The package targets Java 17+ and Spring Boot 3.x
and is shipped as com.adjudon:adjudon-java on Maven Central, with
a adjudon-spring-boot-starter companion that auto-wires the
client into a Spring application context. Runtime dependencies are
limited to Jackson and the JDK's built-in HttpClient; no Apache
HTTP, no Netty, no transitive surprises in a regulated build.
The Java SDK is on the published roadmap with a Maven Central
release target of Q3 2026. Until then, Java integrations call
the Traces API directly with Jackson +
HttpClient; the wire contract is identical and a hand-rolled
client ports cleanly to the SDK once it ships. This page documents
the SDK shape as it will land.
Coordinates
<dependency>
<groupId>com.adjudon</groupId>
<artifactId>adjudon-java</artifactId>
<version>0.1.0</version>
</dependency>
implementation("com.adjudon:adjudon-java:0.1.0")
The Spring Boot starter:
<dependency>
<groupId>com.adjudon</groupId>
<artifactId>adjudon-spring-boot-starter</artifactId>
<version>0.1.0</version>
</dependency>
First call
import com.adjudon.AdjudonClient;
import com.adjudon.TraceRequest;
import com.adjudon.TraceResponse;
AdjudonClient adjudon = AdjudonClient.builder()
.apiKey(System.getenv("ADJUDON_API_KEY")) // adj_agent_<48-hex>
.agentId("customer-support-bot")
.build();
TraceResponse trace = adjudon.trace(TraceRequest.builder()
.inputContext(Map.of("prompt", "Can I get a refund for order #1234?"))
.outputDecision(Map.of("action", "initiate_refund", "confidence", 0.91))
.build());
if ("blocked".equals(trace.getStatus())) {
return "Sorry, I can't process this request right now.";
}
@RestController
public class RefundController {
private final AdjudonClient adjudon;
public RefundController(AdjudonClient adjudon) {
this.adjudon = adjudon;
}
@PostMapping("/refunds")
public ResponseEntity<?> refund(@RequestBody RefundRequest req) {
TraceResponse trace = adjudon.trace(TraceRequest.builder()
.inputContext(req.toInputContext())
.outputDecision(Map.of("action", "initiate_refund", "amount", req.getAmount()))
.build());
return switch (trace.getStatus()) {
case "blocked" -> ResponseEntity.status(403).body(trace);
case "flagged" -> ResponseEntity.status(202).body(trace);
default -> ResponseEntity.ok(trace);
};
}
}
The starter reads adjudon.api-key and adjudon.agent-id from
application.yml or environment variables and registers the
AdjudonClient as a singleton bean.
Versions
| Runtime | Supported |
|---|---|
| Java 17 | ✓ (minimum) |
| Java 21 | ✓ (LTS, recommended) |
| Spring Boot 3.2 | ✓ |
| Spring Boot 3.3 | ✓ |
| Java 11 | — (out of upstream support) |
| Spring Boot 2.x | — (Jakarta EE 9+ migration required) |
Configuration
| Field | Default | Description |
|---|---|---|
apiKey | (required) | adj_agent_<48-hex> |
agentId | (required) | Stable agent identifier |
baseUrl | https://api.adjudon.com | Override for self-hosted Adjudon |
failMode | OPEN | OPEN returns passthrough on failure; CLOSED raises |
timeout | Duration.ofSeconds(10) | HTTP timeout |
maxRetries | 3 | Retry attempts on 429 / 5xx |
Spring Boot configuration
The starter exposes the same fields as application.yml keys:
adjudon:
api-key: ${ADJUDON_API_KEY}
agent-id: customer-support-bot
fail-mode: OPEN
timeout: PT10S
max-retries: 3
A @ConfigurationProperties("adjudon") binding picks each field up
on startup; an unset api-key fails fast with
AdjudonConfigException. Spring profiles work as expected for
splitting test vs production credentials. Actuator-exposed health
contributes adjudonReachable to /actuator/health so a Kubernetes
liveness probe can read the same fail-open posture the SDK
enforces internally.
Idempotency
adjudon.trace(req, idempotencyKey) accepts a string. If omitted,
the SDK generates a UUID per call. Duplicate keys within the
24-hour window return the
cached response, so retry storms during a transient network
hiccup never inflate the org's metered trace count.
Errors
| Exception | Cause |
|---|---|
AdjudonAuthException | Invalid API key; never retried |
AdjudonRateLimitException | Retries exhausted on 429 (only when failMode = CLOSED) |
AdjudonTimeoutException | Retries exhausted on timeout (only when failMode = CLOSED) |
AdjudonBlockedException | Policy returned block; always propagated as a compliance signal |
AdjudonConfigException | Builder argument invalid |
failMode = OPEN returns TraceResponse.passthrough() for every
exception except AdjudonBlockedException and
AdjudonAuthException — the first is a compliance signal
you must not swallow, the second is a configuration bug.
Resources
- Quickstart — first trace in 60 seconds
- Authentication — API key formats and rotation
- Traces API — the underlying HTTP surface this SDK calls (use this directly until the Maven Central release lands)
- Error Codes — HTTP-level errors this SDK raises
- GitHub:
github.com/adjudon/adjudon-java(target repository for source, issues, and releases when the SDK ships)