Java
The Java SDK is an idiomatic, buildable Java library emitted from the same GlottoIR as every
other target. It ships with Gson models and an SDK-managed, Jetty-backed HTTP
transport. Existing java.net.http.HttpClient injection remains supported.
Add the artifact, construct a Client, and call methods — no checked exceptions to wrap.
Quickstart
implementation 'com.your-org:petstore:1.0.0'
import com.your_org.petstore.Client;
Client client = new Client(System.getenv("PETSTORE_TOKEN"));
// resources are reached through an accessor call
var pet = client.pets().createPet(newPet);
// paging is a Stream — bind it, then drain
var pets = client.pets().listPets();
pets.forEach(System.out::println);
Resource sub-clients
Operations hang off resource accessors rather than a flat method list:
client.pets().get(id), client.pets().photos().add(...) — the same service-accessor shape the
other engines emit — and each method carries Javadoc generated from the operation prose in the spec.
Unchecked errors
Non-2xx responses throw ApiError, an unchecked RuntimeException carrying the parsed, typed
error body, so callers narrow with instanceof rather than being forced into try/catch for a
checked IOException. See Errors.
Async twins
Every buffered operation has a CompletableFuture async twin alongside its blocking form, so the
SDK fits both a synchronous caller and a non-blocking pipeline without a second client.
Pagination
List methods return a lazy walker over the API’s pagination strategy (cursor, page, offset, or link-header), fetching each page as you iterate. See Pagination.
Retries & backoff
Transient failures (5xx, 429, transport errors) retry with exponential backoff and jitter,
configurable per client. Discriminated-union response bodies resolve to the right concrete type.
See Retries & timeouts, Streaming, and
Authentication.
Unknown response fields
Your API can add a response field without it being a breaking change — but a generated record has no component to put it in, and Gson discards what it does not recognize. The generated models keep it instead: a field the SDK wasn’t generated from is retained on decode, readable through an accessor, and written back out when the model is re-serialized.
Pet pet = client.pets().createPet(body);
// A field your API started returning after this SDK was generated.
JsonElement species = pet.extraFields().get("species");
// Re-encoding preserves it — a read-modify-write never silently drops it.
String json = client.gson().toJson(pet);
extraFields() is the record’s own accessor and returns an immutable Map<String, JsonElement>,
so nested objects and arrays survive intact, and retention is recursive.
Your existing construction still compiles: the models keep a constructor over their original
component list, so new Pet(id, name, tag, status, photoUrls) is unchanged.
The retained fields are read-only by design. To send a field your spec doesn’t model yet, use the per-call extra-body escape hatch rather than writing to the retained bag.
Pages, request controls, and files
Paginated methods also expose manual pages, so you can inspect one response and request its successor explicitly. Request overrides apply to the initial call and to each requested next page; see Retries & timeouts for precedence and cancellation.
Binary downloads return an owned byte response with metadata, a bounded read helper, and incremental consumption. Close the response when you stop early. Your generated README demonstrates these operations with your API’s names and the language’s native calling conventions.