As I noted in the OP I was thinking it had to be some round about way. I did get it to work, but does not seem "ergonomic"
Added two constants in my GrpcServer class. (Could be moved somewhere else)
public static Metadata.Key<String> JWT_CLAIMS_KEY =
Metadata.Key.of("jwtClaims", Metadata.ASCII_STRING_MARSHALLER);
// The parameter value here is irrelevant and does not need to match the previous one, but useful for debugging.
public static Context.Key<String> JWT_CLAIMS_CONTEXT_KEY = Context.key("jwtClaims");
The interceptor is added to the builder.
.intercept(
new ServerInterceptor() {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
final var context =
Context.current()
withValue(JWT_CLAIMS_CONTEXT_KEY, headers.get(JWT_CLAIMS_KEY));
return Contexts.interceptCall(context, call, headers, next);
}
})
The service implementation uses the Context.get()
method to obtain the value.
@Override
public void echo(
EchoOuterClass.EchoRequest request,
StreamObserver<EchoOuterClass.EchoResponse> responseObserver) {
System.out.println(GrpcServer.JWT_CLAIMS_CONTEXT_KEY.get());
responseObserver.onNext(
EchoOuterClass.EchoResponse.newBuilder().setMessage(request.getMessage()).build());
responseObserver.onCompleted();
}
I guess I was looking for something like...
.intercept(Contexts.serverInterceptorBuilder()
.withMetadataValue(JWT_CLAIMS_KEY, JWT_CONTEXT_CLAIMS_KEY)
.build();
And which would be implemented as something like (note not tested, just writing from my head...)
ServerInterceptorBuilder serverInterceptorBuilder() {
return new ServerInterceptorBuilder(Context.current());
}
private static class ServerInterceptorBuilder {
private Context context;
ServerInterceptorBuilder(Context context) {
this.context = context;
}
public <X> ServerInterceptorBuilder withMetadataValue(
Metadata.Key<X> metadataKey,
Context.Key<X> contextKey) {
context = context.withValue(contextKey, metadataKey);
return this;
}
public ServerInterceptor build() {
return new ServerInterceptor() {
new ServerInterceptor() {
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
ServerCall<ReqT, RespT> call,
Metadata headers,
ServerCallHandler<ReqT, RespT> next) {
return Contexts.interceptCall(context, call, headers, next);
}
};
}
}