announcements

Introducing the Zenmanage Java SDK

The Zenmanage Java SDK is on Maven Central. It ships with a builder-pattern client, context-aware targeting, deterministic percentage rollouts, and Spring Boot auto-configuration that wires a Zenmanage bean straight into dependency injection.

The Zenmanage Java SDK is on Maven Central. It ships with a fluent ConfigBuilder, deterministic percentage rollouts, and Spring Boot auto-configuration that registers a Zenmanage bean ready to inject into any service or controller — no manual wiring required.

Java is the fifth server-side SDK we've shipped this year, following JavaScript, Python, Go, and .NET. If your stack is a Spring Boot service, or any JVM backend that's been proxying flag checks through the REST API by hand, this is the client you've been waiting on.

Why Java

A lot of Java shops are exactly the teams that care most about how a flag client behaves in production: layered Spring services, strict dependency-injection conventions, and change-management processes that don't tolerate a client library that fights the framework. We built the SDK around ConfigBuilder so configuration reads the same way whether you're wiring it by hand in a plain main() or letting Spring Boot assemble it from application.properties. Either way, you get the same Zenmanage client, the same evaluation API, and the same deterministic bucketing underneath.

Key features

Builder-pattern configuration

ConfigBuilder.create() gives you a fluent chain for environment token, cache backend, cache TTL, usage reporting, and API endpoint. ConfigBuilder.fromEnvironment() reads the same settings from environment variables when you'd rather not hardcode them, which is the common case for anything running in a container.

Context-aware targeting

Build a Context from a user or organization, attach attributes, and pass it into evaluation. Rules match against that context the same way whether you're targeting a single user, a percentage rollout, or a segment defined by attribute — and deterministic bucketing means a context lands in the same bucket every time, so ramping a rollout doesn't reshuffle who's already in it.

Spring Boot auto-configuration

Set a handful of zenmanage.* properties and the SDK auto-configures Zenmanage, Config, and FlagManager beans. Inject Zenmanage into any @Service or @RestController through the constructor, same as any other Spring-managed dependency — there's no separate starter artifact to add, it's part of the same zenmanage-java package.

Safe type coercion

Calling the wrong accessor for a flag's type never throws — asBool(), asString(), asNumber(), and asJson() each fall back to a safe zero value instead of a runtime exception. Pass an inline default to single() and a missing flag or a failed rules fetch resolves to that value too, so a network blip doesn't take down a request path.

Getting started

Install from Maven Central with Maven:

<dependency>
  <groupId>com.zenmanage</groupId>
  <artifactId>zenmanage-java</artifactId>
  <version>1.0.0</version>
</dependency>

Or Gradle:

implementation 'com.zenmanage:zenmanage-java:1.0.0'

Configure a client and evaluate a flag:

import com.zenmanage.sdk.Zenmanage;
import com.zenmanage.sdk.config.Config;
import com.zenmanage.sdk.config.ConfigBuilder;

Config config = ConfigBuilder.create()
    .withEnvironmentToken(System.getenv("ZENMANAGE_SERVER_KEY"))
    .build();

Zenmanage zenmanage = new Zenmanage(config);

boolean enabled = zenmanage.flags()
    .single("new-dashboard", false)
    .isEnabled();

if (enabled) {
    System.out.println("Render the new dashboard");
}

Targeting a specific user or organization works the same way, just with a Context attached:

import com.zenmanage.sdk.context.Attribute;
import com.zenmanage.sdk.context.Context;

Context context = Context.single("user", "user-123", "Alice")
    .addAttribute(new Attribute("country").addValue("US"));

boolean premium = zenmanage.flags()
    .withContext(context)
    .single("premium-feature", false)
    .isEnabled();

For a Spring Boot service, skip ConfigBuilder entirely and let auto-configuration wire it from application properties:

# application.properties
zenmanage.environment-token=srv_your_server_key_here
zenmanage.cache-ttl-seconds=3600
zenmanage.cache-backend=memory
zenmanage.usage-reporting=true
import org.springframework.stereotype.Service;
import com.zenmanage.sdk.Zenmanage;

@Service
public class CheckoutService {
    private final Zenmanage zenmanage;

    public CheckoutService(Zenmanage zenmanage) {
        this.zenmanage = zenmanage;
    }

    public boolean newCheckoutEnabled() {
        return zenmanage.flags().single("new-checkout-flow", false).isEnabled();
    }
}

CheckoutService never touches ConfigBuilder or an environment token directly — Spring hands it a fully configured Zenmanage bean through the constructor, same as any other dependency, and you can override the cache backend by defining your own Spring Cache bean if the default in-memory cache doesn't fit your deployment.

What's next

The Java SDK is server-side only — it requires a server token (prefixed srv_) and rejects client or mobile keys at configuration time, the same requirement as our other server SDKs. It's on Maven Central now, source lives on GitHub, and the Java quickstart has the full setup, including the Spring Boot integration and error-handling patterns.

Enjoyed this article?

Share it with your network.