Java SDK
Flipswitch SDK for Java with real-time SSE support
The Flipswitch Java SDK provides an OpenFeature-compatible provider with automatic cache invalidation via Server-Sent Events (SSE).
GitHub: github.com/flipswitch-io/java-sdk
Requirements
- Java 17+
- OpenFeature SDK 1.x
Installation
<dependency>
<groupId>io.flipswitch</groupId>
<artifactId>flipswitch-sdk</artifactId>
</dependency>Check Maven Central for the latest version.
implementation 'io.flipswitch:flipswitch-sdk'Check Maven Central for the latest version.
Quick Start
import io.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.io") // Optional: defaults to production url
.enableRealtime(true) // Optional: defaults to true
.enablePollingFallback(true) // Optional: fall back to polling when SSE fails
.pollingIntervalMs(30000) // Optional: polling interval in milliseconds
.maxSseRetries(5) // Optional: max SSE retries before fallback
.httpClient(customOkHttpClient) // Optional: custom OkHttpClient
.build();| Option | Type | Default | Description |
|---|---|---|---|
apiKey | String | required | Environment API key from dashboard |
baseUrl | String | https://api.flipswitch.io | Your Flipswitch server URL |
enableRealtime | boolean | true | Enable SSE for real-time flag updates |
httpClient | OkHttpClient | default | Custom HTTP client |
enablePollingFallback | boolean | true | Fall back to polling when SSE fails |
pollingIntervalMs | long | 30000 | Polling interval in milliseconds |
maxSseRetries | int | 5 | Max SSE retries before polling fallback |
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:
- The SSE client receives a
flag-updatedorconfig-updatedevent - The local cache is immediately invalidated
- Next flag evaluation fetches the fresh value
Event Listeners
provider.addFlagChangeListener(event -> {
if (event.flagKey() != null) {
System.out.println("Flag changed: " + event.flagKey());
} else {
System.out.println("All flags invalidated");
}
System.out.println("Timestamp: " + event.getTimestampAsInstant());
});Connection Status
// Check current SSE status
SseClient.ConnectionStatus status = provider.getSseStatus();
// CONNECTING, CONNECTED, DISCONNECTED, ERROR
// Force reconnect
provider.reconnectSse();Polling Fallback
When SSE connection fails repeatedly, the SDK falls back to polling:
FlipswitchProvider provider = FlipswitchProvider.builder("YOUR_API_KEY")
.enablePollingFallback(true) // default: true
.pollingIntervalMs(30000) // Poll every 30 seconds
.maxSseRetries(5) // Fall back after 5 failed SSE attempts
.build();
// Check if polling is active
if (provider.isPollingActive()) {
System.out.println("Polling fallback is active");
}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.