Flipswitch

Java SDK

Flipswitch SDK for Java with real-time SSE support

Java SDK

The Flipswitch Java SDK provides an OpenFeature-compatible provider with automatic cache invalidation via Server-Sent Events (SSE).

Requirements

  • Java 17+
  • OpenFeature SDK 1.x

Installation

<dependency>
    <groupId>dev.flipswitch</groupId>
    <artifactId>flipswitch-sdk</artifactId>
    <version>0.1.0</version>
</dependency>

Quick Start

import dev.flipswitch.FlipswitchProvider;
import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.MutableContext;
 
// API key is required, all other options have sensible defaults
FlipswitchProvider provider = FlipswitchProvider.builder("YOUR_API_KEY").build();
 
// Register with OpenFeature
OpenFeatureAPI api = OpenFeatureAPI.getInstance();
api.setProviderAndWait(provider);
 
// Get a client
Client client = api.getClient();
 
// Evaluate flags
boolean darkMode = client.getBooleanValue("dark-mode", false);
String welcome = client.getStringValue("welcome-message", "Hello!");
int maxItems = client.getIntegerValue("max-items-per-page", 10);

Configuration Options

FlipswitchProvider provider = FlipswitchProvider.builder("YOUR_API_KEY")
    .baseUrl("https://api.flipswitch.dev")    // Optional: defaults to production
    .enableRealtime(true)                      // Optional: defaults to true
    .cacheTtl(Duration.ofSeconds(60))          // Optional: defaults to 60s
    .httpClient(customOkHttpClient)            // Optional: custom OkHttpClient
    .build();
OptionTypeDefaultDescription
apiKeyStringrequiredEnvironment API key from dashboard
baseUrlStringhttps://api.flipswitch.devYour Flipswitch server URL
enableRealtimebooleantrueEnable SSE for real-time flag updates
cacheTtlDuration60sCache time-to-live
httpClientOkHttpClientdefaultCustom HTTP client

Evaluation Context

Pass user attributes for targeting:

MutableContext context = new MutableContext("user-123");
context.add("email", "user@example.com");
context.add("plan", "premium");
context.add("country", "SE");
 
boolean showFeature = client.getBooleanValue("new-feature", false, context);

Real-Time Updates

When enableRealtime(true) is set (default), the SDK maintains an SSE connection to receive instant flag changes:

  1. The SSE client receives a flag-change event
  2. The local cache is immediately invalidated
  3. Next flag evaluation fetches the fresh value

Event Listeners

provider.addFlagChangeListener(event -> {
    System.out.println("Flag changed: " + event.getFlagKey());
    System.out.println("Timestamp: " + event.getTimestamp());
});

Connection Status

// Check current SSE status
SseClient.ConnectionStatus status = provider.getSseStatus();
// CONNECTING, CONNECTED, DISCONNECTED, ERROR
 
// Force reconnect
provider.reconnectSse();

Detailed Evaluation

Get full evaluation details including variant and reason:

FlagEvaluationDetails<Boolean> details = client.getBooleanDetails("feature-flag", false, context);
 
System.out.println("Value: " + details.getValue());
System.out.println("Variant: " + details.getVariant());
System.out.println("Reason: " + details.getReason());

Object Flags

For complex flag values (JSON objects):

Value config = client.getObjectValue("feature-config", new Value(), context);
 
// Access structure
if (config.isStructure()) {
    Structure s = config.asStructure();
    String theme = s.getValue("theme").asString();
    int timeout = s.getValue("timeout").asInteger();
}

Bulk Flag Evaluation

Evaluate all flags at once:

// Evaluate all flags
List<FlagEvaluation> flags = provider.evaluateAllFlags(context);
for (FlagEvaluation flag : flags) {
    System.out.println(flag.getKey() + " (" + flag.getValueType() + "): " + flag.getValueAsString());
}
 
// Evaluate a single flag with full details
FlagEvaluation flag = provider.evaluateFlag("dark-mode", context);
if (flag != null) {
    System.out.println("Value: " + flag.getValue());
    System.out.println("Reason: " + flag.getReason());
    System.out.println("Variant: " + flag.getVariant());
}

Spring Boot Integration

@Configuration
public class FeatureFlagConfig {
 
    @Bean
    public FlipswitchProvider flipswitchProvider(
            @Value("${flipswitch.api-key}") String apiKey) {
        return FlipswitchProvider.builder(apiKey).build();
    }
 
    @Bean
    public Client openFeatureClient(FlipswitchProvider provider) throws Exception {
        OpenFeatureAPI api = OpenFeatureAPI.getInstance();
        api.setProviderAndWait(provider);
        return api.getClient();
    }
}

Then inject and use in your services:

@Service
public class MyService {
    private final Client featureClient;
 
    public MyService(Client featureClient) {
        this.featureClient = featureClient;
    }
 
    public void doSomething(User user) {
        MutableContext context = new MutableContext(user.getId());
        context.add("email", user.getEmail());
 
        if (featureClient.getBooleanValue("new-feature", false, context)) {
            // New feature logic
        }
    }
}

application.yml:

flipswitch:
  api-key: ${FLIPSWITCH_API_KEY}

Reconnection Strategy

The SSE client automatically reconnects with exponential backoff:

  • Initial delay: 1 second
  • Maximum delay: 30 seconds
  • Backoff multiplier: 2x

When reconnected, the provider state changes from STALE back to READY.

Shutdown

Always shutdown the provider when done:

provider.shutdown();
// or
OpenFeatureAPI.getInstance().shutdown();

In Spring Boot, the provider will be automatically shut down when the application context closes.

Troubleshooting

SSE connection keeps disconnecting

Check if your proxy or load balancer supports long-lived connections. Configure timeout settings accordingly.

Flags not updating in real-time

Verify that enableRealtime(true) is set and check the SSE status:

System.out.println(provider.getSseStatus());

Memory leaks

Ensure you call shutdown() when the provider is no longer needed, especially in testing scenarios.