Java

Java client for Switchyard feature flags. Java 17+, no dependencies.

java
SwitchyardClient flags = SwitchyardClient.builder(System.getenv("SWITCHYARD_SDK_KEY"))
    .baseUri("https://switchyard.example.com")
    .build();

// Optional: wait briefly for the first fetch. Checks work straight away, returning defaults until then.
flags.awaitReady(Duration.ofSeconds(2));

if (flags.isEnabled("new-checkout", false)) {
    // new code path
}

Create one client per SDK key and share it: it's thread-safe. Close it on shutdown (try-with-resources or your framework's lifecycle).

Flags with variations

Flags that serve text, numbers or JSON instead of on/off have typed methods. Each returns the default before the first fetch, for unknown flags, and for flags of another type:

java
String color = flags.stringVariation("checkout-button", user, "green");
double limit = flags.numberVariation("upload-limit-mb", user, 10);
Object plan = flags.jsonVariation("plan-config", user, Map.of());   // a Map, List, String, number, Boolean or null

Segments and prerequisites arrive with the flags and are evaluated in memory too. A context without a key can still carry attributes: EvaluationContext.anonymousBuilder().attribute("country", "IN").build().

For OpenFeature, see switchyard-openfeature. Evaluation.evaluate(snapshot, flagKey, context) gives a flag's value with the reason for it, outside a client.

Use it in your app

It isn't on Maven Central yet, so build it into your local Maven repository first:

bash
cd clients/java
./mvnw install -DskipTests

Then depend on it:

xml
<dependency>
  <groupId>io.github.nikolaviews</groupId>
  <artifactId>switchyard-java</artifactId>
  <version>0.1.0-SNAPSHOT</version>
</dependency>

With Gradle, add mavenLocal() to your repositories and implementation("io.github.nikolaviews:switchyard-java:0.1.0-SNAPSHOT").

Pass the SDK key through configuration (an environment variable or a secrets manager), never in source code. Each environment (development, production) has its own key.

Targeting and rollouts

Flags with targeting rules or percentage rollouts need to know who the check is for:

java
EvaluationContext user = EvaluationContext.builder(userId)   // a stable ID: same user, same key
    .attribute("email", user.email().toLowerCase())
    .attribute("country", user.country())
    .build();

if (flags.isEnabled("new-checkout", user, false)) { ... }

The exact rules, shared by every Switchyard library, are in spec/EVALUATION.md; the shared test vectors run as part of this library's tests.

How it behaves

Situation What isEnabled(key, context, default) returns
Before the first fetch default
Flag switched off false (off overrides every rule)
Flag on the first matching rule's result, else the fallthrough's, for this context
Flag unknown (never created, archived, misspelled) default
Server down, slow, or returning errors the last values it received; retries with exponential backoff and jitter
SDK key rejected (rotated or revoked) the last values it received
After close() the last values it received; no more polling

Options

Builder method Default
baseUri http://localhost:8080 The Switchyard server
pollInterval 30 s How often to check for changes while not streaming (minimum 100 ms); every 5 min while streaming
requestTimeout 10 s Connect and response timeout per request
maxBackoff 5 min Longest wait between retries while failing
httpClient a new HttpClient Bring your own, e.g. for a proxy or custom TLS
streaming true Listen for changes over Server-Sent Events; false to rely on polling alone

Build

bash
./mvnw verify