Google API Extensions for Java providing gRPC-specific functionality for Google Cloud client libraries
—
Comprehensive interceptor support for headers, logging, metadata handling, and custom request/response processing.
Provider interface for supplying custom gRPC ClientInterceptors to the channel.
/**
* Provider for custom gRPC ClientInterceptors
* Allows injection of custom interceptors into the gRPC call chain
*/
public interface GrpcInterceptorProvider {
/** Get list of client interceptors to apply */
List<ClientInterceptor> getInterceptors();
}
/**
* Static factory methods for common interceptor providers
*/
public class GrpcInterceptorProviders {
/** Create provider with single interceptor */
public static GrpcInterceptorProvider create(ClientInterceptor interceptor);
/** Create provider with multiple interceptors */
public static GrpcInterceptorProvider create(List<ClientInterceptor> interceptors);
/** Create empty provider */
public static GrpcInterceptorProvider empty();
/** Combine multiple providers */
public static GrpcInterceptorProvider combine(GrpcInterceptorProvider... providers);
}Built-in interceptor for managing request headers with dynamic header injection.
/**
* Interceptor for managing gRPC request headers
* Supports static headers and dynamic header providers
*/
public class GrpcHeaderInterceptor implements ClientInterceptor {
/** Create interceptor with static headers */
public static GrpcHeaderInterceptor create(Map<String, String> headers);
/** Create interceptor with header provider */
public static GrpcHeaderInterceptor create(HeaderProvider headerProvider);
/** Intercept gRPC call to add headers */
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next);
}Interceptor for extracting and processing response metadata from gRPC calls.
/**
* Interceptor for handling gRPC response metadata
* Extracts headers and trailers from responses
*/
public class GrpcMetadataHandlerInterceptor implements ClientInterceptor {
/** Create metadata handler interceptor */
public static GrpcMetadataHandlerInterceptor create(ResponseMetadataHandler handler);
/** Intercept call to handle metadata */
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next);
}Response metadata handler providing access to gRPC headers and trailers.
/**
* Handler for gRPC response metadata
* Provides access to headers and trailers from responses
*/
public class GrpcResponseMetadata implements ResponseMetadata {
/** Create response metadata handler */
public static GrpcResponseMetadata create();
/** Get response headers as metadata map */
public Map<String, List<String>> getMetadata();
/** Get response trailers metadata */
public List<String> getTrailersMetadata();
/** Get specific header values */
public List<String> getMetadata(String key);
/** Get trailer value for key */
public String getTrailerValue(String key);
/** Check if metadata contains key */
public boolean containsKey(String key);
/** Get all metadata keys */
public Set<String> getKeys();
}Handler interface for processing response metadata from gRPC calls.
/**
* Handler interface for processing response metadata
* Called when response metadata is received
*/
public interface ResponseMetadataHandler {
/** Handle response headers */
void onHeaders(Metadata headers);
/** Handle response trailers */
void onTrailers(Metadata trailers);
/** Handle both headers and trailers */
default void onMetadata(Metadata headers, Metadata trailers) {
onHeaders(headers);
onTrailers(trailers);
}
}Built-in interceptor for logging gRPC requests and responses.
/**
* Interceptor for logging gRPC calls
* Supports configurable logging levels and content filtering
*/
public class GrpcLoggingInterceptor implements ClientInterceptor {
/** Create logging interceptor with default settings */
public static GrpcLoggingInterceptor create();
/** Create logging interceptor with logger */
public static GrpcLoggingInterceptor create(Logger logger);
/** Create logging interceptor with configuration */
public static GrpcLoggingInterceptor create(LoggingConfig config);
/** Intercept call for logging */
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next);
}
/**
* Configuration for gRPC logging interceptor
*/
public static class GrpcLoggingInterceptor.LoggingConfig {
/** Set whether to log request payloads */
public LoggingConfig logRequestPayloads(boolean enabled);
/** Set whether to log response payloads */
public LoggingConfig logResponsePayloads(boolean enabled);
/** Set whether to log metadata */
public LoggingConfig logMetadata(boolean enabled);
/** Set logging level */
public LoggingConfig logLevel(Level level);
/** Set maximum payload size to log */
public LoggingConfig maxPayloadSize(int maxSize);
/** Set logger instance */
public LoggingConfig logger(Logger logger);
}/**
* Utilities for managing interceptor chains
*/
public class InterceptorChainUtils {
/** Create interceptor chain from providers */
public static ClientInterceptor chainInterceptors(List<GrpcInterceptorProvider> providers);
/** Add interceptor to existing chain */
public static ClientInterceptor addInterceptor(ClientInterceptor chain, ClientInterceptor interceptor);
/** Remove interceptor from chain by type */
public static ClientInterceptor removeInterceptor(ClientInterceptor chain, Class<?> interceptorType);
/** Get interceptors of specific type from chain */
public static <T extends ClientInterceptor> List<T> getInterceptors(ClientInterceptor chain, Class<T> type);
}/**
* Base class for custom interceptors with common functionality
*/
public abstract class BaseGrpcInterceptor implements ClientInterceptor {
/** Protected constructor for subclasses */
protected BaseGrpcInterceptor();
/** Template method for call interception */
public final <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next);
/** Override this method in subclasses */
protected abstract <ReqT, RespT> ClientCall<ReqT, RespT> doInterceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next);
/** Utility method to create forwarding call */
protected <ReqT, RespT> ForwardingClientCall<ReqT, RespT> createForwardingCall(
ClientCall<ReqT, RespT> delegate);
}
/**
* Base class for simple interceptors that only modify requests
*/
public abstract class SimpleRequestInterceptor extends BaseGrpcInterceptor {
/** Override to modify requests */
protected abstract <ReqT> ReqT modifyRequest(ReqT request, MethodDescriptor<ReqT, ?> method);
}
/**
* Base class for simple interceptors that only modify responses
*/
public abstract class SimpleResponseInterceptor extends BaseGrpcInterceptor {
/** Override to modify responses */
protected abstract <RespT> RespT modifyResponse(RespT response, MethodDescriptor<?, RespT> method);
}/**
* Provider for dynamic headers
* Allows headers to be computed at request time
*/
public interface HeaderProvider {
/** Get headers map */
Map<String, String> getHeaders();
/** Get headers for specific method */
default Map<String, String> getHeaders(MethodDescriptor<?, ?> method) {
return getHeaders();
}
}
/**
* Static header provider implementations
*/
public class HeaderProviders {
/** Create provider with static headers */
public static HeaderProvider create(Map<String, String> headers);
/** Create provider with single header */
public static HeaderProvider create(String key, String value);
/** Create empty header provider */
public static HeaderProvider empty();
/** Combine multiple header providers */
public static HeaderProvider combine(HeaderProvider... providers);
/** Create provider from supplier */
public static HeaderProvider fromSupplier(Supplier<Map<String, String>> supplier);
}/**
* Utilities for working with gRPC metadata
*/
public class MetadataUtils {
/** Convert map to gRPC Metadata */
public static Metadata mapToMetadata(Map<String, String> headers);
/** Convert gRPC Metadata to map */
public static Map<String, List<String>> metadataToMap(Metadata metadata);
/** Extract specific header from metadata */
public static String getHeader(Metadata metadata, String key);
/** Check if metadata contains header */
public static boolean hasHeader(Metadata metadata, String key);
/** Create metadata key */
public static Metadata.Key<String> createKey(String name);
/** Create binary metadata key */
public static Metadata.Key<byte[]> createBinaryKey(String name);
}import com.google.api.gax.grpc.GrpcHeaderInterceptor;
import java.util.Map;
// Create header interceptor with static headers
Map<String, String> headers = Map.of(
"x-custom-header", "custom-value",
"x-client-version", "1.0.0"
);
GrpcHeaderInterceptor headerInterceptor = GrpcHeaderInterceptor.create(headers);
// Use with channel provider
InstantiatingGrpcChannelProvider channelProvider =
InstantiatingGrpcChannelProvider.newBuilder()
.setInterceptorProvider(GrpcInterceptorProviders.create(headerInterceptor))
.build();import com.google.api.gax.rpc.HeaderProvider;
// Create dynamic header provider
HeaderProvider dynamicHeaders = new HeaderProvider() {
@Override
public Map<String, String> getHeaders() {
return Map.of(
"x-request-id", UUID.randomUUID().toString(),
"x-timestamp", String.valueOf(System.currentTimeMillis())
);
}
};
GrpcHeaderInterceptor headerInterceptor = GrpcHeaderInterceptor.create(dynamicHeaders);import com.google.api.gax.grpc.GrpcMetadataHandlerInterceptor;
import com.google.api.gax.grpc.ResponseMetadataHandler;
import io.grpc.Metadata;
// Create metadata handler
ResponseMetadataHandler metadataHandler = new ResponseMetadataHandler() {
@Override
public void onHeaders(Metadata headers) {
String requestId = headers.get(Metadata.Key.of("x-request-id", Metadata.ASCII_STRING_MARSHALLER));
System.out.println("Request ID: " + requestId);
}
@Override
public void onTrailers(Metadata trailers) {
String processingTime = trailers.get(Metadata.Key.of("x-processing-time", Metadata.ASCII_STRING_MARSHALLER));
System.out.println("Processing time: " + processingTime + "ms");
}
};
GrpcMetadataHandlerInterceptor metadataInterceptor =
GrpcMetadataHandlerInterceptor.create(metadataHandler);import com.google.api.gax.grpc.GrpcLoggingInterceptor;
import java.util.logging.Level;
import java.util.logging.Logger;
// Create logging interceptor with configuration
Logger logger = Logger.getLogger("grpc.calls");
GrpcLoggingInterceptor.LoggingConfig config = new GrpcLoggingInterceptor.LoggingConfig()
.logRequestPayloads(true)
.logResponsePayloads(false)
.logMetadata(true)
.logLevel(Level.INFO)
.maxPayloadSize(1024)
.logger(logger);
GrpcLoggingInterceptor loggingInterceptor = GrpcLoggingInterceptor.create(config);import io.grpc.ClientInterceptor;
import io.grpc.CallOptions;
import io.grpc.Channel;
import io.grpc.ClientCall;
import io.grpc.ForwardingClientCall;
import io.grpc.Metadata;
import io.grpc.MethodDescriptor;
// Custom authentication interceptor
public class AuthenticationInterceptor implements ClientInterceptor {
private final String authToken;
public AuthenticationInterceptor(String authToken) {
this.authToken = authToken;
}
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next) {
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
// Add authorization header
headers.put(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER),
"Bearer " + authToken);
super.start(responseListener, headers);
}
};
}
}
// Use the custom interceptor
AuthenticationInterceptor authInterceptor = new AuthenticationInterceptor("your-token");
GrpcInterceptorProvider interceptorProvider = GrpcInterceptorProviders.create(authInterceptor);import java.util.List;
// Combine multiple interceptors
List<ClientInterceptor> interceptors = List.of(
new AuthenticationInterceptor("token"),
GrpcHeaderInterceptor.create(Map.of("x-client", "java-client")),
GrpcLoggingInterceptor.create(),
GrpcMetadataHandlerInterceptor.create(metadataHandler)
);
GrpcInterceptorProvider combinedProvider = GrpcInterceptorProviders.create(interceptors);
// Use with channel provider
InstantiatingGrpcChannelProvider channelProvider =
InstantiatingGrpcChannelProvider.newBuilder()
.setInterceptorProvider(combinedProvider)
.build();// Custom request transformation interceptor
public class RequestTransformInterceptor extends SimpleRequestInterceptor {
@Override
protected <ReqT> ReqT modifyRequest(ReqT request, MethodDescriptor<ReqT, ?> method) {
// Transform request (example: add timestamp)
if (request instanceof MyRequest) {
MyRequest myRequest = (MyRequest) request;
return (ReqT) myRequest.toBuilder()
.setTimestamp(System.currentTimeMillis())
.build();
}
return request;
}
}
// Custom response transformation interceptor
public class ResponseTransformInterceptor extends SimpleResponseInterceptor {
@Override
protected <RespT> RespT modifyResponse(RespT response, MethodDescriptor<?, RespT> method) {
// Transform response (example: log response size)
if (response instanceof Message) {
Message message = (Message) response;
System.out.println("Response size: " + message.getSerializedSize() + " bytes");
}
return response;
}
}// Interceptor that applies conditionally based on method
public class ConditionalInterceptor implements ClientInterceptor {
private final Set<String> targetMethods;
private final ClientInterceptor targetInterceptor;
public ConditionalInterceptor(Set<String> targetMethods, ClientInterceptor targetInterceptor) {
this.targetMethods = targetMethods;
this.targetInterceptor = targetInterceptor;
}
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions,
Channel next) {
// Apply interceptor only to target methods
if (targetMethods.contains(method.getFullMethodName())) {
return targetInterceptor.interceptCall(method, callOptions, next);
} else {
return next.newCall(method, callOptions);
}
}
}
// Use conditional interceptor
Set<String> criticalMethods = Set.of(
"MyService/CriticalMethod1",
"MyService/CriticalMethod2"
);
ConditionalInterceptor conditionalInterceptor = new ConditionalInterceptor(
criticalMethods,
GrpcLoggingInterceptor.create()
);Install with Tessl CLI
npx tessl i tessl/maven-com-google-api--gax-grpc