Skip to main content

Generated Java protobuf and gRPC client for Flaggr

Last updated April 4, 2026

Java SDK

Generated Java protobuf types and gRPC service stubs for Flaggr. Use standard gRPC-Java to connect.

Installation

Maven

<dependencies>
  <dependency>
    <groupId>dev.flaggr</groupId>
    <artifactId>flaggr-proto</artifactId>
    <version>0.1.0</version>
  </dependency>
  <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-netty-shaded</artifactId>
    <version>1.62.2</version>
  </dependency>
  <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-protobuf</artifactId>
    <version>1.62.2</version>
  </dependency>
  <dependency>
    <groupId>io.grpc</groupId>
    <artifactId>grpc-stub</artifactId>
    <version>1.62.2</version>
  </dependency>
</dependencies>

Gradle

dependencies {
    implementation 'dev.flaggr:flaggr-proto:0.1.0'
    implementation 'io.grpc:grpc-netty-shaded:1.62.2'
    implementation 'io.grpc:grpc-protobuf:1.62.2'
    implementation 'io.grpc:grpc-stub:1.62.2'
}

gRPC Client Setup

import dev.flaggr.proto.v1.*;
import io.grpc.ManagedChannel;
import io.grpc.ManagedChannelBuilder;
 
public class FlaggrClient {
    private final EvaluationServiceGrpc.EvaluationServiceBlockingStub evaluationStub;
    private final FlagStreamServiceGrpc.FlagStreamServiceStub streamStub;
    private final ManagedChannel channel;
 
    public FlaggrClient(String host, int port) {
        this.channel = ManagedChannelBuilder.forAddress(host, port)
            .useTransportSecurity()
            .build();
        this.evaluationStub = EvaluationServiceGrpc.newBlockingStub(channel);
        this.streamStub = FlagStreamServiceGrpc.newStub(channel);
    }
 
    public void shutdown() throws InterruptedException {
        channel.shutdown().awaitTermination(5, java.util.concurrent.TimeUnit.SECONDS);
    }
}

Flag Evaluation

Boolean

EvaluationContext context = EvaluationContext.newBuilder()
    .setTargetingKey("user-456")
    .putStringAttributes("plan", "enterprise")
    .putStringAttributes("country", "AU")
    .build();
 
ResolveBooleanResponse resp = evaluationStub.resolveBoolean(
    ResolveBooleanRequest.newBuilder()
        .setFlagKey("checkout-v2")
        .setDefaultValue(false)
        .setContext(context)
        .setServiceId("web-app")
        .build()
);
 
System.out.printf("checkout-v2 = %s (reason: %s)%n", resp.getValue(), resp.getReason());

String

ResolveStringResponse resp = evaluationStub.resolveString(
    ResolveStringRequest.newBuilder()
        .setFlagKey("button-color")
        .setDefaultValue("blue")
        .setContext(context)
        .setServiceId("web-app")
        .build()
);

Number

ResolveNumberResponse resp = evaluationStub.resolveNumber(
    ResolveNumberRequest.newBuilder()
        .setFlagKey("rate-limit")
        .setDefaultValue(100.0)
        .setContext(context)
        .setServiceId("web-app")
        .build()
);

Object (JSON)

ResolveObjectResponse resp = evaluationStub.resolveObject(
    ResolveObjectRequest.newBuilder()
        .setFlagKey("banner-config")
        .setDefaultValue("{\"text\":\"\",\"color\":\"blue\",\"dismissible\":true}")
        .setContext(context)
        .setServiceId("web-app")
        .build()
);

Bulk Evaluation

BulkEvaluateFlagsResponse resp = evaluationStub.bulkEvaluateFlags(
    BulkEvaluateFlagsRequest.newBuilder()
        .addFlagKeys("checkout-v2")
        .addFlagKeys("dark-mode")
        .addFlagKeys("rate-limit")
        .setContext(context)
        .setServiceId("web-app")
        .build()
);
 
resp.getFlagsMap().forEach((key, result) -> {
    System.out.printf("%s = %s (reason: %s)%n", key, result.getValue(), result.getReason());
});

Streaming

Subscribe to real-time flag updates with server-side streaming:

import io.grpc.stub.StreamObserver;
 
streamStub.streamFlags(
    StreamFlagsRequest.newBuilder()
        .setServiceId("web-app")
        .setEnvironment(Environment.ENVIRONMENT_PRODUCTION)
        .setClientId("java-service-01")
        .setApiToken("flg_your_token")
        .build(),
    new StreamObserver<FlagUpdate>() {
        @Override
        public void onNext(FlagUpdate update) {
            switch (update.getEventType()) {
                case FLAG_EVENT_TYPE_UPDATED:
                    System.out.printf("flag %s updated%n", update.getFlagKey());
                    break;
                case FLAG_EVENT_TYPE_TOGGLED:
                    System.out.printf("flag %s toggled%n", update.getFlagKey());
                    break;
                case FLAG_EVENT_TYPE_HEARTBEAT:
                    // connection alive
                    break;
                default:
                    break;
            }
        }
 
        @Override
        public void onError(Throwable t) {
            System.err.println("Stream error: " + t.getMessage());
        }
 
        @Override
        public void onCompleted() {
            System.out.println("Stream completed");
        }
    }
);

OpenFeature Integration

Use with the OpenFeature Java SDK:

import dev.openfeature.sdk.OpenFeatureAPI;
import dev.openfeature.sdk.Client;
import dev.openfeature.sdk.MutableContext;
 
public class Main {
    public static void main(String[] args) {
        OpenFeatureAPI api = OpenFeatureAPI.getInstance();
 
        // Register the Flaggr provider
        api.setProvider(new FlaggrProvider("flaggr.dev", 443, "web-app", "flg_your_token"));
 
        Client client = api.getClient();
 
        MutableContext ctx = new MutableContext("user-456");
        ctx.add("plan", "enterprise");
        ctx.add("country", "AU");
 
        boolean value = client.getBooleanValue("checkout-v2", false, ctx);
        System.out.printf("checkout-v2 = %s%n", value);
    }
}

The FlaggrProvider wraps the gRPC client and implements the FeatureProvider interface. See the OpenFeature Java SDK docs for more on evaluation context, hooks, and event handling.

Async Client

For non-blocking evaluation, use the async stub:

EvaluationServiceGrpc.EvaluationServiceFutureStub asyncStub =
    EvaluationServiceGrpc.newFutureStub(channel);
 
ListenableFuture<ResolveBooleanResponse> future = asyncStub.resolveBoolean(
    ResolveBooleanRequest.newBuilder()
        .setFlagKey("checkout-v2")
        .setDefaultValue(false)
        .setContext(context)
        .setServiceId("web-app")
        .build()
);
 
// Add callback or block on result
Futures.addCallback(future, new FutureCallback<ResolveBooleanResponse>() {
    @Override
    public void onSuccess(ResolveBooleanResponse result) {
        System.out.printf("checkout-v2 = %s%n", result.getValue());
    }
 
    @Override
    public void onFailure(Throwable t) {
        System.err.println("Evaluation failed: " + t.getMessage());
    }
}, MoreExecutors.directExecutor());