Java

View as Markdown

The Unleash Java SDK lets you evaluate feature flags in Java applications. It connects to Unleash or Unleash Edge to fetch flag configurations and evaluates them locally against an Unleash context.

You can use this SDK with Unleash Enterprise or Unleash Open Source.

For an overview of how Unleash SDKs work, including offline behavior, feature compatibility across SDKs, and default refresh and metrics intervals, refer to the SDK overview.

Requirements

Java versionSDK version
Java 11 or laterSDK v11.0.0 or later
Java 8SDK v10.2.x or earlier

Installation

You need to add the Unleash SDK as a dependency for your project. Here’s how you would add it to your pom.xml and build.gradle file:

pom.xml

1<dependency>
2 <groupId>io.getunleash</groupId>
3 <artifactId>unleash-client-java</artifactId>
4 <version>Latest version here</version>
5</dependency>

build.gradle

1 implementation("io.getunleash:unleash-client-java:$unleashedVersion")

Initialization

In almost every case, you only want a single, shared instance of the Unleash class (a singleton) in your application. You would typically use a dependency injection framework (such as Spring or Guice) to inject it where you need it. Having multiple instances of the client in your application could lead to inconsistencies and performance degradation.

The SDK synchronizes with the Unleash API on initialization. By default this happens asynchronously in the background. If you need to block until the SDK has synchronized, use the synchronousFetchOnInitialisation option.

For a full overview of options, see configuration options.

Asynchronous initialization:

1UnleashConfig config = UnleashConfig.builder()
2 .appName("my.java-app")
3 .instanceId("your-instance-1")
4 .unleashAPI("<unleash-api-url>")
5 .apiKey("<client-api-token>")
6 .build();
7
8Unleash unleash = new DefaultUnleash(config);

Synchronous initialization:

1UnleashConfig config = UnleashConfig.builder()
2 .appName("my.java-app")
3 .instanceId("your-instance-1")
4 .unleashAPI("<unleash-api-url>")
5 .apiKey("<client-api-token>")
6 .synchronousFetchOnInitialisation(true)
7 .build();
8
9Unleash unleash = new DefaultUnleash(config);

Check flags

With the SDK initialized, you can use the isEnabled method to check the state of your feature toggles. The method returns a boolean indicating whether a feature is enabled for the current request.

1if(unleash.isEnabled("AwesomeFeature")) {
2 // new feature behavior
3} else {
4 // current behavior
5}

The isEnabled method also accepts a second boolean argument. The SDK uses this as a fallback value if it can’t find the feature you’re trying to check. For example, if unleash.isEnabled("non-existing-toggle") returns false when "non-existing-toggle" doesn’t exist, calling unleash.isEnabled("non-existing-toggle", true), will return true.

You can also pass an Unleash context to evaluate flags for a specific user, session, or other properties required by strategies, constraints, and stickiness. Refer to the Unleash context section for details.

Custom strategies

The Java client comes with implementations for the built-in activation strategies provided by Unleash. Read more about the strategies in the activation strategies reference documentation.

To add a custom strategy, implement the Strategy interface and register it when you set up Unleash:

1Strategy s1 = new MyAwesomeStrategy();
2Strategy s2 = new MySuperAwesomeStrategy();
3Unleash unleash = new DefaultUnleash(config, s1, s2);

Unleash context

In order to use some of the common activation strategies you must provide an Unleash context. This client SDK provides two ways of providing the Unleash context:

Inline context

Pass the context directly as an argument to the isEnabled call:

1UnleashContext context = UnleashContext.builder()
2 .userId("user@mail.com").build();
3
4unleash.isEnabled("someToggle", context);

Context provider

For a more advanced approach, configure an UnleashContextProvider so you don’t need to pass the context to every isEnabled call.

The provider typically binds the context to the same thread as the request. If you use Spring, the UnleashContextProvider will typically be a request-scoped bean.

1UnleashContextProvider contextProvider = new MyAwesomeContextProvider();
2
3UnleashConfig config = new UnleashConfig.Builder()
4 .appName("java-test")
5 .instanceId("instance x")
6 .unleashAPI("http://unleash.herokuapp.com/api/")
7 .apiKey("<client-api-token>")
8 .unleashContextProvider(contextProvider)
9 .build();
10
11Unleash unleash = new DefaultUnleash(config);
12
13// Anywhere in the code unleash will get the unleash context from your registered provider.
14unleash.isEnabled("someToggle");

Custom HTTP headers

If you want the client to send custom HTTP Headers with all requests to the Unleash API you can define that by setting them via the UnleashConfig.

1UnleashConfig unleashConfig = UnleashConfig.builder()
2 .appName("my-app")
3 .instanceId("my-instance-1")
4 .unleashAPI(unleashAPI)
5 .apiKey("12312Random")
6 .customHttpHeader("<name>", "<value>")
7 .build();

Dynamic custom HTTP headers

If you need custom HTTP headers that change during the lifetime of the client, a provider can be defined via the UnleashConfig.

1public class CustomHttpHeadersProviderImpl implements CustomHttpHeadersProvider {
2 @Override
3 public Map<String, String> getCustomHeaders() {
4 String token = "Acquire or refresh token";
5 return new HashMap() {{ put("Authorization", "Bearer "+token); }};
6 }
7}
1CustomHttpHeadersProvider provider = new CustomHttpHeadersProviderImpl();
2
3UnleashConfig unleashConfig = UnleashConfig.builder()
4 .appName("my-app")
5 .instanceId("my-instance-1")
6 .unleashAPI(unleashAPI)
7 .apiKey("API token")
8 .customHttpHeadersProvider(provider)
9 .build();

Events

Introduced in 3.2.2

Sometimes you want to know when Unleash updates internally. This can be achieved by registering a subscriber. An example on how to configure a custom subscriber is shown below. Have a look at UnleashSubscriber.java to get a complete overview of all methods you can override.

1UnleashConfig unleashConfig = UnleashConfig.builder()
2 .appName("my-app")
3 .instanceId("my-instance-1")
4 .unleashAPI(unleashAPI)
5 .apiKey("API token")
6 .subscriber(new UnleashSubscriber() {
7 @Override
8 public void onReady(UnleashReady ready) {
9 System.out.println("Unleash is ready");
10 }
11 @Override
12 public void togglesFetched(FeatureToggleResponse toggleResponse) {
13 System.out.println("Fetch toggles with status: " + toggleResponse.getStatus());
14 }
15
16 @Override
17 public void togglesBackedUp(ToggleCollection toggleCollection) {
18 System.out.println("Backup stored.");
19 }
20
21 })
22 .build();

Polling options

  • appName - Required. Should be a unique name identifying the client application using Unleash.
  • synchronousFetchOnInitialisation - Allows the user to specify that the Unleash client should do one synchronous fetch to the unleash-api at initialisation. This will slow down the initialisation (the client must wait for an HTTP response). If the unleash-api is unavailable the client will silently move on and assume the api will be available later.
  • disablePolling - Stops the client from polling. If used without synchronousFetchOnInitialisation will cause the client to never fetch toggles from the unleash-api.
  • fetchTogglesInterval - Sets the interval (in seconds) between each poll to the unleash-api. Set this to 0 to do a single fetch and then stop refreshing while the process lives.

Outbound network proxy

The Unleash Java client uses HttpURLConnection as its HTTP client, which automatically recognizes common JVM proxy settings such as http.proxyHost and http.proxyPort. If your proxy does not require authentication, it works without additional configuration. However, if you have to use Basic Authentication, settings such as http.proxyUser and http.proxyPassword are not recognized by default. To enable Basic Authentication for an HTTP proxy, enable the following option on the configuration builder:

1UnleashConfig config = UnleashConfig.builder()
2 .appName("my-app")
3 .unleashAPI("http://unleash.org")
4 .apiKey("API token")
5 .enableProxyAuthenticationByJvmProperties()
6 .build();

Custom toggle fetcher

The Unleash Java client supports using your own toggle fetcher. The Config builder has been expanded to accept an io.getunleash.util.UnleashFeatureFetcherFactory which should be a Function<UnleashConfig, FeatureFetcher>. If you want to use OkHttp instead of HttpURLConnection you’ll need a dependency on okhttp

1<dependency>
2 <groupId>com.squareup.okhttp3</groupId>
3 <artifactId>okhttp</artifactId>
4 <version>4.10+</version>
5</dependency>

Then you can change your config to

1UnleashConfig config = UnleashConfig.builder()
2 .appName("my-app")
3 .unleashAPI("http://unleash.org")
4 .apiKey("API token")
5 .unleashFeatureFetcherFactory(OkHttpFeatureFetcher::new)
6 .build();

This will then start using OkHttp instead of HttpURLConnection.

Custom metrics sender

The Unleash Java client supports using your own metrics sender. The Config builder has been expanded to accept a io.getunleash.util.MetricsSenderFactory which should be a Function<UnleashConfig, MetricsSender>.

If you want to use OkHttp instead of HttpURLConnection you’ll need a dependency on okhttp

1<dependency>
2 <groupId>com.squareup.okhttp3</groupId>
3 <artifactId>okhttp</artifactId>
4 <version>4.10+</version>
5</dependency>

Then you can change your config to

1UnleashConfig config = UnleashConfig.builder()
2 .appName("my-app")
3 .unleashAPI("http://unleash.org")
4 .customHttpHeader("Authorization", "API token")
5 .unleashMetricsSenderFactory(OkHttpMetricsSender::new)
6 .build();

This will then start using OkHttp instead of HttpURLConnection to send metrics.

Local caching and offline behavior

By default unleash-client fetches the feature flags from unleash-server every 15s, and stores the result in unleash-repo.json which is located in the java.io.tmpdir directory. This means that if the unleash-server becomes unavailable, the unleash-client will still be able to toggle the features based on the values stored in unleash-repo.json.

As a result of this, the second argument of isEnabled will be returned in two cases:

  • When unleash-repo.json does not exist.
  • When the named feature toggle does not exist in unleash-repo.json.

Bootstrap

Unleash supports bootstrapping from a JSON string. You can configure your own custom provider implementing the ToggleBootstrapProvider interface’s single method String read(). This should return a JSON string in the same format returned from /api/client/features.

Example bootstrap files can be found in the JSON files located in src/test/resources.

This setup can be useful for applications deployed to ephemeral containers or restricted file systems where Unleash’s need to write the backup file is not desirable or possible.

ToggleBootstrapFileProvider

Unleash comes configured with a ToggleBootstrapFileProvider which implements the ToggleBootstrapProvider interface. This is the default implementation used if not overridden via the setToggleBootstrapProvider on UnleashConfig.

Configure ToggleBootstrapFileProvider

The ToggleBootstrapFileProvider reads the file located at the path defined by the UNLEASH_BOOTSTRAP_FILE environment variable. It supports both classpath: paths and absolute file paths.

Unit testing

You might want to control the state of the toggles during unit testing. Unleash comes with a FakeUnleash implementation for doing this.

Example usage:

1// example 1: everything on
2FakeUnleash fakeUnleash = new FakeUnleash();
3fakeUnleash.enableAll();
4
5assertThat(fakeUnleash.isEnabled("unknown"), is(true));
6assertThat(fakeUnleash.isEnabled("unknown2"), is(true));
7
8// example 2
9FakeUnleash fakeUnleash = new FakeUnleash();
10fakeUnleash.enable("t1", "t2");
11
12assertThat(fakeUnleash.isEnabled("t1"), is(true));
13assertThat(fakeUnleash.isEnabled("t2"), is(true));
14assertThat(fakeUnleash.isEnabled("unknown"), is(false));
15
16// example 3: variants
17FakeUnleash fakeUnleash = new FakeUnleash();
18fakeUnleash.enable("t1", "t2");
19fakeUnleash.setVariant("t1", new Variant("a", (String) null, true, true));
20
21assertThat(fakeUnleash.getVariant("t1").getName(), is("a"));

See more in FakeUnleashTest.java

Configuration options

The UnleashConfig$Builder class (created via UnleashConfig.builder()) exposes a set of builder methods to configure your Unleash client. The available options are listed below with a description of what they do. For the full signatures, take a look at the UnleashConfig class definition.

Method nameDescriptionRequiredDefault value
apiKeyThe API key to use for authenticating against the Unleash API.Yesnull
appNameThe name of the application as shown in the Unleash UI. Registered applications are listed on the Applications page.Yesnull
backupFileThe path to the file where local backups get stored.NoSynthesized from your system’s java.io.tmpdir and your appName: "<java.io.tmpdir>/unleash-<appName>-repo.json"
customHttpHeaderAdd a custom HTTP header to the list of HTTP headers that will the client sends to the Unleash API. Each method call will add a new header. Note: in most cases, you’ll need to use this method to provide an API token.NoN/A
customHttpHeadersProviderAdd a custom HTTP header provider. Useful for dynamic custom HTTP headers.Nonull
disablePollingA boolean indicating whether the client should poll the Unleash API for updates to toggles.
disableMetricsA boolean indicating whether the client should disable sending usage metrics to the Unleash server.Nofalse
enableProxyAuthenticationByJvmPropertiesEnable support for using JVM properties for HTTP proxy authentication.Nofalse
environmentThe value to set for the Unleash context’s environment property. Not the same as Unleash’s environments.Nonull
fallbackStrategyA strategy implementation that the client can use if it doesn’t recognize the strategy type returned from the server.Nonull
fetchTogglesIntervalHow often (in seconds) the client should check for toggle updates. Set to 0 if you want to only check once.No15
instanceIdA unique(-ish) identifier for your instance. Typically a hostname, pod id or something similar. Unleash uses this to separate metrics from the client SDKs with the same appName.Yesnull
namePrefixIf provided, the client will only fetch toggles whose name starts with the provided value.Nonull
projectNameIf provided, the client will only fetch toggles from the specified project. (This can also be achieved with an API token).Nonull
proxyA Proxy object. Use this to configure a third-party proxy that sits between your client and the Unleash server.Nonull
scheduledExecutorA custom executor to control timing and running of tasks (such as fetching toggles, sending metrics).NoUnleashScheduledExecutorImpl
sendMetricsIntervalHow often (in seconds) the client should send metrics to the Unleash server. Ignored if you disable metrics with the disableMetrics method.No60
subscriberRegister a subscriber to Unleash client events.Nonull
synchronousFetchOnInitialisationWhether the client should fetch toggle configuration synchronously (in a blocking manner) on initialisation.Nofalse
toggleBootstrapProviderAdd a bootstrap provider (must implement the ToggleBootstrapProvider interface)No
unleashAPIThe URL of the Unleash API.Yesnull
unleashContextProviderAn Unleash context provider used to configure Unleash.Nonull
unleashFeatureFetcherFactoryA factory providing a FeatureFetcher implementation.NoHttpFeatureFetcher::new
unleashMetricsSenderFactoryA factory providing a MetricSender implementation.NoDefaultHttpMetricsSender::new
startupExceptionHandlerHandler for the behavior in the event of an error when starting the client.Nonull

When you have set all the desired options, initialize the configuration with the build method. You can then pass the configuration to the Unleash client constructor. As an example:

1UnleashConfig config = UnleashConfig.builder()
2 .appName("your app name")
3 .instanceId("instance id")
4 .unleashAPI("http://unleash.herokuapp.com/api/")
5 .apiKey("API token")
6 // ... more configuration options
7 .build();
8
9Unleash unleash = new DefaultUnleash(config);

Migrating to v10

If you’re using MoreOperations, custom or fallback strategies, subscribers or bootstrapping, see the full v10 migration guide. If you use GraalVM or Quarkus, hold off on upgrading to v10 — support is planned but not yet implemented.