0
# Interceptors and Metadata
1
2
Comprehensive interceptor support for headers, logging, metadata handling, and custom request/response processing.
3
4
## Capabilities
5
6
### GrpcInterceptorProvider
7
8
Provider interface for supplying custom gRPC ClientInterceptors to the channel.
9
10
```java { .api }
11
/**
12
* Provider for custom gRPC ClientInterceptors
13
* Allows injection of custom interceptors into the gRPC call chain
14
*/
15
public interface GrpcInterceptorProvider {
16
/** Get list of client interceptors to apply */
17
List<ClientInterceptor> getInterceptors();
18
}
19
20
/**
21
* Static factory methods for common interceptor providers
22
*/
23
public class GrpcInterceptorProviders {
24
/** Create provider with single interceptor */
25
public static GrpcInterceptorProvider create(ClientInterceptor interceptor);
26
27
/** Create provider with multiple interceptors */
28
public static GrpcInterceptorProvider create(List<ClientInterceptor> interceptors);
29
30
/** Create empty provider */
31
public static GrpcInterceptorProvider empty();
32
33
/** Combine multiple providers */
34
public static GrpcInterceptorProvider combine(GrpcInterceptorProvider... providers);
35
}
36
```
37
38
### GrpcHeaderInterceptor
39
40
Built-in interceptor for managing request headers with dynamic header injection.
41
42
```java { .api }
43
/**
44
* Interceptor for managing gRPC request headers
45
* Supports static headers and dynamic header providers
46
*/
47
public class GrpcHeaderInterceptor implements ClientInterceptor {
48
/** Create interceptor with static headers */
49
public static GrpcHeaderInterceptor create(Map<String, String> headers);
50
51
/** Create interceptor with header provider */
52
public static GrpcHeaderInterceptor create(HeaderProvider headerProvider);
53
54
/** Intercept gRPC call to add headers */
55
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
56
MethodDescriptor<ReqT, RespT> method,
57
CallOptions callOptions,
58
Channel next);
59
}
60
```
61
62
### GrpcMetadataHandlerInterceptor
63
64
Interceptor for extracting and processing response metadata from gRPC calls.
65
66
```java { .api }
67
/**
68
* Interceptor for handling gRPC response metadata
69
* Extracts headers and trailers from responses
70
*/
71
public class GrpcMetadataHandlerInterceptor implements ClientInterceptor {
72
/** Create metadata handler interceptor */
73
public static GrpcMetadataHandlerInterceptor create(ResponseMetadataHandler handler);
74
75
/** Intercept call to handle metadata */
76
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
77
MethodDescriptor<ReqT, RespT> method,
78
CallOptions callOptions,
79
Channel next);
80
}
81
```
82
83
### GrpcResponseMetadata
84
85
Response metadata handler providing access to gRPC headers and trailers.
86
87
```java { .api }
88
/**
89
* Handler for gRPC response metadata
90
* Provides access to headers and trailers from responses
91
*/
92
public class GrpcResponseMetadata implements ResponseMetadata {
93
/** Create response metadata handler */
94
public static GrpcResponseMetadata create();
95
96
/** Get response headers as metadata map */
97
public Map<String, List<String>> getMetadata();
98
99
/** Get response trailers metadata */
100
public List<String> getTrailersMetadata();
101
102
/** Get specific header values */
103
public List<String> getMetadata(String key);
104
105
/** Get trailer value for key */
106
public String getTrailerValue(String key);
107
108
/** Check if metadata contains key */
109
public boolean containsKey(String key);
110
111
/** Get all metadata keys */
112
public Set<String> getKeys();
113
}
114
```
115
116
### ResponseMetadataHandler
117
118
Handler interface for processing response metadata from gRPC calls.
119
120
```java { .api }
121
/**
122
* Handler interface for processing response metadata
123
* Called when response metadata is received
124
*/
125
public interface ResponseMetadataHandler {
126
/** Handle response headers */
127
void onHeaders(Metadata headers);
128
129
/** Handle response trailers */
130
void onTrailers(Metadata trailers);
131
132
/** Handle both headers and trailers */
133
default void onMetadata(Metadata headers, Metadata trailers) {
134
onHeaders(headers);
135
onTrailers(trailers);
136
}
137
}
138
```
139
140
### GrpcLoggingInterceptor
141
142
Built-in interceptor for logging gRPC requests and responses.
143
144
```java { .api }
145
/**
146
* Interceptor for logging gRPC calls
147
* Supports configurable logging levels and content filtering
148
*/
149
public class GrpcLoggingInterceptor implements ClientInterceptor {
150
/** Create logging interceptor with default settings */
151
public static GrpcLoggingInterceptor create();
152
153
/** Create logging interceptor with logger */
154
public static GrpcLoggingInterceptor create(Logger logger);
155
156
/** Create logging interceptor with configuration */
157
public static GrpcLoggingInterceptor create(LoggingConfig config);
158
159
/** Intercept call for logging */
160
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
161
MethodDescriptor<ReqT, RespT> method,
162
CallOptions callOptions,
163
Channel next);
164
}
165
166
/**
167
* Configuration for gRPC logging interceptor
168
*/
169
public static class GrpcLoggingInterceptor.LoggingConfig {
170
/** Set whether to log request payloads */
171
public LoggingConfig logRequestPayloads(boolean enabled);
172
173
/** Set whether to log response payloads */
174
public LoggingConfig logResponsePayloads(boolean enabled);
175
176
/** Set whether to log metadata */
177
public LoggingConfig logMetadata(boolean enabled);
178
179
/** Set logging level */
180
public LoggingConfig logLevel(Level level);
181
182
/** Set maximum payload size to log */
183
public LoggingConfig maxPayloadSize(int maxSize);
184
185
/** Set logger instance */
186
public LoggingConfig logger(Logger logger);
187
}
188
```
189
190
## Interceptor Utilities
191
192
### Interceptor Chain Management
193
194
```java { .api }
195
/**
196
* Utilities for managing interceptor chains
197
*/
198
public class InterceptorChainUtils {
199
/** Create interceptor chain from providers */
200
public static ClientInterceptor chainInterceptors(List<GrpcInterceptorProvider> providers);
201
202
/** Add interceptor to existing chain */
203
public static ClientInterceptor addInterceptor(ClientInterceptor chain, ClientInterceptor interceptor);
204
205
/** Remove interceptor from chain by type */
206
public static ClientInterceptor removeInterceptor(ClientInterceptor chain, Class<?> interceptorType);
207
208
/** Get interceptors of specific type from chain */
209
public static <T extends ClientInterceptor> List<T> getInterceptors(ClientInterceptor chain, Class<T> type);
210
}
211
```
212
213
### Custom Interceptor Base Classes
214
215
```java { .api }
216
/**
217
* Base class for custom interceptors with common functionality
218
*/
219
public abstract class BaseGrpcInterceptor implements ClientInterceptor {
220
/** Protected constructor for subclasses */
221
protected BaseGrpcInterceptor();
222
223
/** Template method for call interception */
224
public final <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
225
MethodDescriptor<ReqT, RespT> method,
226
CallOptions callOptions,
227
Channel next);
228
229
/** Override this method in subclasses */
230
protected abstract <ReqT, RespT> ClientCall<ReqT, RespT> doInterceptCall(
231
MethodDescriptor<ReqT, RespT> method,
232
CallOptions callOptions,
233
Channel next);
234
235
/** Utility method to create forwarding call */
236
protected <ReqT, RespT> ForwardingClientCall<ReqT, RespT> createForwardingCall(
237
ClientCall<ReqT, RespT> delegate);
238
}
239
240
/**
241
* Base class for simple interceptors that only modify requests
242
*/
243
public abstract class SimpleRequestInterceptor extends BaseGrpcInterceptor {
244
/** Override to modify requests */
245
protected abstract <ReqT> ReqT modifyRequest(ReqT request, MethodDescriptor<ReqT, ?> method);
246
}
247
248
/**
249
* Base class for simple interceptors that only modify responses
250
*/
251
public abstract class SimpleResponseInterceptor extends BaseGrpcInterceptor {
252
/** Override to modify responses */
253
protected abstract <RespT> RespT modifyResponse(RespT response, MethodDescriptor<?, RespT> method);
254
}
255
```
256
257
## Header and Metadata Types
258
259
### Header Provider Interface
260
261
```java { .api }
262
/**
263
* Provider for dynamic headers
264
* Allows headers to be computed at request time
265
*/
266
public interface HeaderProvider {
267
/** Get headers map */
268
Map<String, String> getHeaders();
269
270
/** Get headers for specific method */
271
default Map<String, String> getHeaders(MethodDescriptor<?, ?> method) {
272
return getHeaders();
273
}
274
}
275
276
/**
277
* Static header provider implementations
278
*/
279
public class HeaderProviders {
280
/** Create provider with static headers */
281
public static HeaderProvider create(Map<String, String> headers);
282
283
/** Create provider with single header */
284
public static HeaderProvider create(String key, String value);
285
286
/** Create empty header provider */
287
public static HeaderProvider empty();
288
289
/** Combine multiple header providers */
290
public static HeaderProvider combine(HeaderProvider... providers);
291
292
/** Create provider from supplier */
293
public static HeaderProvider fromSupplier(Supplier<Map<String, String>> supplier);
294
}
295
```
296
297
### Metadata Utilities
298
299
```java { .api }
300
/**
301
* Utilities for working with gRPC metadata
302
*/
303
public class MetadataUtils {
304
/** Convert map to gRPC Metadata */
305
public static Metadata mapToMetadata(Map<String, String> headers);
306
307
/** Convert gRPC Metadata to map */
308
public static Map<String, List<String>> metadataToMap(Metadata metadata);
309
310
/** Extract specific header from metadata */
311
public static String getHeader(Metadata metadata, String key);
312
313
/** Check if metadata contains header */
314
public static boolean hasHeader(Metadata metadata, String key);
315
316
/** Create metadata key */
317
public static Metadata.Key<String> createKey(String name);
318
319
/** Create binary metadata key */
320
public static Metadata.Key<byte[]> createBinaryKey(String name);
321
}
322
```
323
324
## Usage Examples
325
326
### Basic Header Interceptor
327
328
```java
329
import com.google.api.gax.grpc.GrpcHeaderInterceptor;
330
import java.util.Map;
331
332
// Create header interceptor with static headers
333
Map<String, String> headers = Map.of(
334
"x-custom-header", "custom-value",
335
"x-client-version", "1.0.0"
336
);
337
338
GrpcHeaderInterceptor headerInterceptor = GrpcHeaderInterceptor.create(headers);
339
340
// Use with channel provider
341
InstantiatingGrpcChannelProvider channelProvider =
342
InstantiatingGrpcChannelProvider.newBuilder()
343
.setInterceptorProvider(GrpcInterceptorProviders.create(headerInterceptor))
344
.build();
345
```
346
347
### Dynamic Header Provider
348
349
```java
350
import com.google.api.gax.rpc.HeaderProvider;
351
352
// Create dynamic header provider
353
HeaderProvider dynamicHeaders = new HeaderProvider() {
354
@Override
355
public Map<String, String> getHeaders() {
356
return Map.of(
357
"x-request-id", UUID.randomUUID().toString(),
358
"x-timestamp", String.valueOf(System.currentTimeMillis())
359
);
360
}
361
};
362
363
GrpcHeaderInterceptor headerInterceptor = GrpcHeaderInterceptor.create(dynamicHeaders);
364
```
365
366
### Response Metadata Handling
367
368
```java
369
import com.google.api.gax.grpc.GrpcMetadataHandlerInterceptor;
370
import com.google.api.gax.grpc.ResponseMetadataHandler;
371
import io.grpc.Metadata;
372
373
// Create metadata handler
374
ResponseMetadataHandler metadataHandler = new ResponseMetadataHandler() {
375
@Override
376
public void onHeaders(Metadata headers) {
377
String requestId = headers.get(Metadata.Key.of("x-request-id", Metadata.ASCII_STRING_MARSHALLER));
378
System.out.println("Request ID: " + requestId);
379
}
380
381
@Override
382
public void onTrailers(Metadata trailers) {
383
String processingTime = trailers.get(Metadata.Key.of("x-processing-time", Metadata.ASCII_STRING_MARSHALLER));
384
System.out.println("Processing time: " + processingTime + "ms");
385
}
386
};
387
388
GrpcMetadataHandlerInterceptor metadataInterceptor =
389
GrpcMetadataHandlerInterceptor.create(metadataHandler);
390
```
391
392
### Logging Interceptor Configuration
393
394
```java
395
import com.google.api.gax.grpc.GrpcLoggingInterceptor;
396
import java.util.logging.Level;
397
import java.util.logging.Logger;
398
399
// Create logging interceptor with configuration
400
Logger logger = Logger.getLogger("grpc.calls");
401
GrpcLoggingInterceptor.LoggingConfig config = new GrpcLoggingInterceptor.LoggingConfig()
402
.logRequestPayloads(true)
403
.logResponsePayloads(false)
404
.logMetadata(true)
405
.logLevel(Level.INFO)
406
.maxPayloadSize(1024)
407
.logger(logger);
408
409
GrpcLoggingInterceptor loggingInterceptor = GrpcLoggingInterceptor.create(config);
410
```
411
412
### Custom Authentication Interceptor
413
414
```java
415
import io.grpc.ClientInterceptor;
416
import io.grpc.CallOptions;
417
import io.grpc.Channel;
418
import io.grpc.ClientCall;
419
import io.grpc.ForwardingClientCall;
420
import io.grpc.Metadata;
421
import io.grpc.MethodDescriptor;
422
423
// Custom authentication interceptor
424
public class AuthenticationInterceptor implements ClientInterceptor {
425
private final String authToken;
426
427
public AuthenticationInterceptor(String authToken) {
428
this.authToken = authToken;
429
}
430
431
@Override
432
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
433
MethodDescriptor<ReqT, RespT> method,
434
CallOptions callOptions,
435
Channel next) {
436
437
return new ForwardingClientCall.SimpleForwardingClientCall<ReqT, RespT>(
438
next.newCall(method, callOptions)) {
439
440
@Override
441
public void start(Listener<RespT> responseListener, Metadata headers) {
442
// Add authorization header
443
headers.put(Metadata.Key.of("authorization", Metadata.ASCII_STRING_MARSHALLER),
444
"Bearer " + authToken);
445
super.start(responseListener, headers);
446
}
447
};
448
}
449
}
450
451
// Use the custom interceptor
452
AuthenticationInterceptor authInterceptor = new AuthenticationInterceptor("your-token");
453
GrpcInterceptorProvider interceptorProvider = GrpcInterceptorProviders.create(authInterceptor);
454
```
455
456
### Multiple Interceptors
457
458
```java
459
import java.util.List;
460
461
// Combine multiple interceptors
462
List<ClientInterceptor> interceptors = List.of(
463
new AuthenticationInterceptor("token"),
464
GrpcHeaderInterceptor.create(Map.of("x-client", "java-client")),
465
GrpcLoggingInterceptor.create(),
466
GrpcMetadataHandlerInterceptor.create(metadataHandler)
467
);
468
469
GrpcInterceptorProvider combinedProvider = GrpcInterceptorProviders.create(interceptors);
470
471
// Use with channel provider
472
InstantiatingGrpcChannelProvider channelProvider =
473
InstantiatingGrpcChannelProvider.newBuilder()
474
.setInterceptorProvider(combinedProvider)
475
.build();
476
```
477
478
### Request/Response Transformation Interceptor
479
480
```java
481
// Custom request transformation interceptor
482
public class RequestTransformInterceptor extends SimpleRequestInterceptor {
483
@Override
484
protected <ReqT> ReqT modifyRequest(ReqT request, MethodDescriptor<ReqT, ?> method) {
485
// Transform request (example: add timestamp)
486
if (request instanceof MyRequest) {
487
MyRequest myRequest = (MyRequest) request;
488
return (ReqT) myRequest.toBuilder()
489
.setTimestamp(System.currentTimeMillis())
490
.build();
491
}
492
return request;
493
}
494
}
495
496
// Custom response transformation interceptor
497
public class ResponseTransformInterceptor extends SimpleResponseInterceptor {
498
@Override
499
protected <RespT> RespT modifyResponse(RespT response, MethodDescriptor<?, RespT> method) {
500
// Transform response (example: log response size)
501
if (response instanceof Message) {
502
Message message = (Message) response;
503
System.out.println("Response size: " + message.getSerializedSize() + " bytes");
504
}
505
return response;
506
}
507
}
508
```
509
510
### Conditional Interceptor
511
512
```java
513
// Interceptor that applies conditionally based on method
514
public class ConditionalInterceptor implements ClientInterceptor {
515
private final Set<String> targetMethods;
516
private final ClientInterceptor targetInterceptor;
517
518
public ConditionalInterceptor(Set<String> targetMethods, ClientInterceptor targetInterceptor) {
519
this.targetMethods = targetMethods;
520
this.targetInterceptor = targetInterceptor;
521
}
522
523
@Override
524
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(
525
MethodDescriptor<ReqT, RespT> method,
526
CallOptions callOptions,
527
Channel next) {
528
529
// Apply interceptor only to target methods
530
if (targetMethods.contains(method.getFullMethodName())) {
531
return targetInterceptor.interceptCall(method, callOptions, next);
532
} else {
533
return next.newCall(method, callOptions);
534
}
535
}
536
}
537
538
// Use conditional interceptor
539
Set<String> criticalMethods = Set.of(
540
"MyService/CriticalMethod1",
541
"MyService/CriticalMethod2"
542
);
543
544
ConditionalInterceptor conditionalInterceptor = new ConditionalInterceptor(
545
criticalMethods,
546
GrpcLoggingInterceptor.create()
547
);
548
```