• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 The gRPC Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package io.grpc;
18 
19 import com.google.common.base.Preconditions;
20 import java.util.List;
21 import java.util.Map;
22 import java.util.concurrent.Executor;
23 import java.util.concurrent.TimeUnit;
24 import javax.annotation.Nullable;
25 
26 /**
27  * A builder for {@link ManagedChannel} instances.
28  *
29  * @param <T> The concrete type of this builder.
30  */
31 public abstract class ManagedChannelBuilder<T extends ManagedChannelBuilder<T>> {
32   /**
33    * Creates a channel with the target's address and port number.
34    *
35    * @see #forTarget(String)
36    * @since 1.0.0
37    */
forAddress(String name, int port)38   public static ManagedChannelBuilder<?> forAddress(String name, int port) {
39     return ManagedChannelProvider.provider().builderForAddress(name, port);
40   }
41 
42   /**
43    * Creates a channel with a target string, which can be either a valid {@link
44    * NameResolver}-compliant URI, or an authority string.
45    *
46    * <p>A {@code NameResolver}-compliant URI is an absolute hierarchical URI as defined by {@link
47    * java.net.URI}. Example URIs:
48    * <ul>
49    *   <li>{@code "dns:///foo.googleapis.com:8080"}</li>
50    *   <li>{@code "dns:///foo.googleapis.com"}</li>
51    *   <li>{@code "dns:///%5B2001:db8:85a3:8d3:1319:8a2e:370:7348%5D:443"}</li>
52    *   <li>{@code "dns://8.8.8.8/foo.googleapis.com:8080"}</li>
53    *   <li>{@code "dns://8.8.8.8/foo.googleapis.com"}</li>
54    *   <li>{@code "zookeeper://zk.example.com:9900/example_service"}</li>
55    * </ul>
56    *
57    * <p>An authority string will be converted to a {@code NameResolver}-compliant URI, which has
58    * the scheme from the name resolver with the highest priority (e.g. {@code "dns"}),
59    * no authority, and the original authority string as its path after properly escaped.
60    * We recommend libraries to specify the schema explicitly if it is known, since libraries cannot
61    * know which NameResolver will be default during runtime.
62    * Example authority strings:
63    * <ul>
64    *   <li>{@code "localhost"}</li>
65    *   <li>{@code "127.0.0.1"}</li>
66    *   <li>{@code "localhost:8080"}</li>
67    *   <li>{@code "foo.googleapis.com:8080"}</li>
68    *   <li>{@code "127.0.0.1:8080"}</li>
69    *   <li>{@code "[2001:db8:85a3:8d3:1319:8a2e:370:7348]"}</li>
70    *   <li>{@code "[2001:db8:85a3:8d3:1319:8a2e:370:7348]:443"}</li>
71    * </ul>
72    *
73    * @since 1.0.0
74    */
forTarget(String target)75   public static ManagedChannelBuilder<?> forTarget(String target) {
76     return ManagedChannelProvider.provider().builderForTarget(target);
77   }
78 
79   /**
80    * Execute application code directly in the transport thread.
81    *
82    * <p>Depending on the underlying transport, using a direct executor may lead to substantial
83    * performance improvements. However, it also requires the application to not block under
84    * any circumstances.
85    *
86    * <p>Calling this method is semantically equivalent to calling {@link #executor(Executor)} and
87    * passing in a direct executor. However, this is the preferred way as it may allow the transport
88    * to perform special optimizations.
89    *
90    * @return this
91    * @since 1.0.0
92    */
directExecutor()93   public abstract T directExecutor();
94 
95   /**
96    * Provides a custom executor.
97    *
98    * <p>It's an optional parameter. If the user has not provided an executor when the channel is
99    * built, the builder will use a static cached thread pool.
100    *
101    * <p>The channel won't take ownership of the given executor. It's caller's responsibility to
102    * shut down the executor when it's desired.
103    *
104    * @return this
105    * @since 1.0.0
106    */
executor(Executor executor)107   public abstract T executor(Executor executor);
108 
109   /**
110    * Provides a custom executor that will be used for operations that block or are expensive.
111    *
112    * <p>It's an optional parameter. If the user has not provided an executor when the channel is
113    * built, the builder will use a static cached thread pool.
114    *
115    * <p>The channel won't take ownership of the given executor. It's caller's responsibility to shut
116    * down the executor when it's desired.
117    *
118    * @return this
119    * @throws UnsupportedOperationException if unsupported
120    * @since 1.25.0
121    */
offloadExecutor(Executor executor)122   public T offloadExecutor(Executor executor) {
123     throw new UnsupportedOperationException();
124   }
125 
126   /**
127    * Adds interceptors that will be called before the channel performs its real work. This is
128    * functionally equivalent to using {@link ClientInterceptors#intercept(Channel, List)}, but while
129    * still having access to the original {@code ManagedChannel}. Interceptors run in the reverse
130    * order in which they are added, just as with consecutive calls to {@code
131    * ClientInterceptors.intercept()}.
132    *
133    * @return this
134    * @since 1.0.0
135    */
intercept(List<ClientInterceptor> interceptors)136   public abstract T intercept(List<ClientInterceptor> interceptors);
137 
138   /**
139    * Adds interceptors that will be called before the channel performs its real work. This is
140    * functionally equivalent to using {@link ClientInterceptors#intercept(Channel,
141    * ClientInterceptor...)}, but while still having access to the original {@code ManagedChannel}.
142    * Interceptors run in the reverse order in which they are added, just as with consecutive calls
143    * to {@code ClientInterceptors.intercept()}.
144    *
145    * @return this
146    * @since 1.0.0
147    */
intercept(ClientInterceptor... interceptors)148   public abstract T intercept(ClientInterceptor... interceptors);
149 
150   /**
151    * Provides a custom {@code User-Agent} for the application.
152    *
153    * <p>It's an optional parameter. The library will provide a user agent independent of this
154    * option. If provided, the given agent will prepend the library's user agent information.
155    *
156    * @return this
157    * @since 1.0.0
158    */
userAgent(String userAgent)159   public abstract T userAgent(String userAgent);
160 
161   /**
162    * Overrides the authority used with TLS and HTTP virtual hosting. It does not change what host is
163    * actually connected to. Is commonly in the form {@code host:port}.
164    *
165    * <p>If the channel builder overrides authority, any authority override from name resolution
166    * result (via {@link EquivalentAddressGroup#ATTR_AUTHORITY_OVERRIDE}) will be discarded.
167    *
168    * <p>This method is intended for testing, but may safely be used outside of tests as an
169    * alternative to DNS overrides.
170    *
171    * @return this
172    * @since 1.0.0
173    */
overrideAuthority(String authority)174   public abstract T overrideAuthority(String authority);
175 
176   /**
177    * Use of a plaintext connection to the server. By default a secure connection mechanism
178    * such as TLS will be used.
179    *
180    * <p>Should only be used for testing or for APIs where the use of such API or the data
181    * exchanged is not sensitive.
182    *
183    * <p>This assumes prior knowledge that the target of this channel is using plaintext.  It will
184    * not perform HTTP/1.1 upgrades.
185    *
186    * @return this
187    * @throws IllegalStateException if ChannelCredentials were provided when constructing the builder
188    * @throws UnsupportedOperationException if plaintext mode is not supported.
189    * @since 1.11.0
190    */
usePlaintext()191   public T usePlaintext() {
192     throw new UnsupportedOperationException();
193   }
194 
195   /**
196    * Makes the client use TLS.
197    *
198    * @return this
199    * @throws IllegalStateException if ChannelCredentials were provided when constructing the builder
200    * @throws UnsupportedOperationException if transport security is not supported.
201    * @since 1.9.0
202    */
203   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/3713")
useTransportSecurity()204   public T useTransportSecurity() {
205     throw new UnsupportedOperationException();
206   }
207 
208   /**
209    * Provides a custom {@link NameResolver.Factory} for the channel. If this method is not called,
210    * the builder will try the providers registered in the default {@link NameResolverRegistry} for
211    * the given target.
212    *
213    * <p>This method should rarely be used, as name resolvers should provide a {@code
214    * NameResolverProvider} and users rely on service loading to find implementations in the class
215    * path. That allows application's configuration to easily choose the name resolver via the
216    * 'target' string passed to {@link ManagedChannelBuilder#forTarget(String)}.
217    *
218    * @return this
219    * @since 1.0.0
220    * @deprecated Most usages should use a globally-registered {@link NameResolverProvider} instead,
221    *     with either the SPI mechanism or {@link NameResolverRegistry#register}. Replacements for
222    *     all use-cases are not necessarily available yet. See
223    *     <a href="https://github.com/grpc/grpc-java/issues/7133">#7133</a>.
224    */
225   @Deprecated
226   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1770")
nameResolverFactory(NameResolver.Factory resolverFactory)227   public abstract T nameResolverFactory(NameResolver.Factory resolverFactory);
228 
229   /**
230    * Sets the default load-balancing policy that will be used if the service config doesn't specify
231    * one.  If not set, the default will be the "pick_first" policy.
232    *
233    * <p>Policy implementations are looked up in the
234    * {@link LoadBalancerRegistry#getDefaultRegistry default LoadBalancerRegistry}.
235    *
236    * <p>This method is implemented by all stock channel builders that are shipped with gRPC, but may
237    * not be implemented by custom channel builders, in which case this method will throw.
238    *
239    * @return this
240    * @since 1.18.0
241    */
242   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1771")
defaultLoadBalancingPolicy(String policy)243   public T defaultLoadBalancingPolicy(String policy) {
244     throw new UnsupportedOperationException();
245   }
246 
247   /**
248    * Enables full-stream decompression of inbound streams. This will cause the channel's outbound
249    * headers to advertise support for GZIP compressed streams, and gRPC servers which support the
250    * feature may respond with a GZIP compressed stream.
251    *
252    * <p>EXPERIMENTAL: This method is here to enable an experimental feature, and may be changed or
253    * removed once the feature is stable.
254    *
255    * @throws UnsupportedOperationException if unsupported
256    * @since 1.7.0
257    */
258   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/3399")
enableFullStreamDecompression()259   public T enableFullStreamDecompression() {
260     throw new UnsupportedOperationException();
261   }
262 
263   /**
264    * Set the decompression registry for use in the channel. This is an advanced API call and
265    * shouldn't be used unless you are using custom message encoding. The default supported
266    * decompressors are in {@link DecompressorRegistry#getDefaultInstance}.
267    *
268    * @return this
269    * @since 1.0.0
270    */
271   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1704")
decompressorRegistry(DecompressorRegistry registry)272   public abstract T decompressorRegistry(DecompressorRegistry registry);
273 
274   /**
275    * Set the compression registry for use in the channel.  This is an advanced API call and
276    * shouldn't be used unless you are using custom message encoding.   The default supported
277    * compressors are in {@link CompressorRegistry#getDefaultInstance}.
278    *
279    * @return this
280    * @since 1.0.0
281    */
282   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/1704")
compressorRegistry(CompressorRegistry registry)283   public abstract T compressorRegistry(CompressorRegistry registry);
284 
285   /**
286    * Set the duration without ongoing RPCs before going to idle mode.
287    *
288    * <p>In idle mode the channel shuts down all connections, the NameResolver and the
289    * LoadBalancer. A new RPC would take the channel out of idle mode. A channel starts in idle mode.
290    * Defaults to 30 minutes.
291    *
292    * <p>This is an advisory option. Do not rely on any specific behavior related to this option.
293    *
294    * @return this
295    * @since 1.0.0
296    */
297   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/2022")
idleTimeout(long value, TimeUnit unit)298   public abstract T idleTimeout(long value, TimeUnit unit);
299 
300   /**
301    * Sets the maximum message size allowed to be received on the channel. If not called,
302    * defaults to 4 MiB. The default provides protection to clients who haven't considered the
303    * possibility of receiving large messages while trying to be large enough to not be hit in normal
304    * usage.
305    *
306    * <p>This method is advisory, and implementations may decide to not enforce this.  Currently,
307    * the only known transport to not enforce this is {@code InProcessTransport}.
308    *
309    * @param bytes the maximum number of bytes a single message can be.
310    * @return this
311    * @throws IllegalArgumentException if bytes is negative.
312    * @since 1.1.0
313    */
maxInboundMessageSize(int bytes)314   public T maxInboundMessageSize(int bytes) {
315     // intentional noop rather than throw, this method is only advisory.
316     Preconditions.checkArgument(bytes >= 0, "bytes must be >= 0");
317     return thisT();
318   }
319 
320   /**
321    * Sets the maximum size of metadata allowed to be received. {@code Integer.MAX_VALUE} disables
322    * the enforcement. The default is implementation-dependent, but is not generally less than 8 KiB
323    * and may be unlimited.
324    *
325    * <p>This is cumulative size of the metadata. The precise calculation is
326    * implementation-dependent, but implementations are encouraged to follow the calculation used for
327    * <a href="http://httpwg.org/specs/rfc7540.html#rfc.section.6.5.2">
328    * HTTP/2's SETTINGS_MAX_HEADER_LIST_SIZE</a>. It sums the bytes from each entry's key and value,
329    * plus 32 bytes of overhead per entry.
330    *
331    * @param bytes the maximum size of received metadata
332    * @return this
333    * @throws IllegalArgumentException if bytes is non-positive
334    * @since 1.17.0
335    */
maxInboundMetadataSize(int bytes)336   public T maxInboundMetadataSize(int bytes) {
337     Preconditions.checkArgument(bytes > 0, "maxInboundMetadataSize must be > 0");
338     // intentional noop rather than throw, this method is only advisory.
339     return thisT();
340   }
341 
342   /**
343    * Sets the time without read activity before sending a keepalive ping. An unreasonably small
344    * value might be increased, and {@code Long.MAX_VALUE} nano seconds or an unreasonably large
345    * value will disable keepalive. Defaults to infinite.
346    *
347    * <p>Clients must receive permission from the service owner before enabling this option.
348    * Keepalives can increase the load on services and are commonly "invisible" making it hard to
349    * notice when they are causing excessive load. Clients are strongly encouraged to use only as
350    * small of a value as necessary.
351    *
352    * @throws UnsupportedOperationException if unsupported
353    * @since 1.7.0
354    */
keepAliveTime(long keepAliveTime, TimeUnit timeUnit)355   public T keepAliveTime(long keepAliveTime, TimeUnit timeUnit) {
356     throw new UnsupportedOperationException();
357   }
358 
359   /**
360    * Sets the time waiting for read activity after sending a keepalive ping. If the time expires
361    * without any read activity on the connection, the connection is considered dead. An unreasonably
362    * small value might be increased. Defaults to 20 seconds.
363    *
364    * <p>This value should be at least multiple times the RTT to allow for lost packets.
365    *
366    * @throws UnsupportedOperationException if unsupported
367    * @since 1.7.0
368    */
keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit)369   public T keepAliveTimeout(long keepAliveTimeout, TimeUnit timeUnit) {
370     throw new UnsupportedOperationException();
371   }
372 
373   /**
374    * Sets whether keepalive will be performed when there are no outstanding RPC on a connection.
375    * Defaults to {@code false}.
376    *
377    * <p>Clients must receive permission from the service owner before enabling this option.
378    * Keepalives on unused connections can easilly accidentally consume a considerable amount of
379    * bandwidth and CPU. {@link ManagedChannelBuilder#idleTimeout idleTimeout()} should generally be
380    * used instead of this option.
381    *
382    * @throws UnsupportedOperationException if unsupported
383    * @see #keepAliveTime(long, TimeUnit)
384    * @since 1.7.0
385    */
keepAliveWithoutCalls(boolean enable)386   public T keepAliveWithoutCalls(boolean enable) {
387     throw new UnsupportedOperationException();
388   }
389 
390   /**
391    * Sets the maximum number of retry attempts that may be configured by the service config. If the
392    * service config specifies a larger value it will be reduced to this value.  Setting this number
393    * to zero is not effectively the same as {@code disableRetry()} because the former does not
394    * disable
395    * <a
396    * href="https://github.com/grpc/proposal/blob/master/A6-client-retries.md#transparent-retries">
397    * transparent retry</a>.
398    *
399    * <p>This method may not work as expected for the current release because retry is not fully
400    * implemented yet.
401    *
402    * @return this
403    * @since 1.11.0
404    */
405   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/3982")
maxRetryAttempts(int maxRetryAttempts)406   public T maxRetryAttempts(int maxRetryAttempts) {
407     throw new UnsupportedOperationException();
408   }
409 
410   /**
411    * Sets the maximum number of hedged attempts that may be configured by the service config. If the
412    * service config specifies a larger value it will be reduced to this value.
413    *
414    * <p>This method may not work as expected for the current release because retry is not fully
415    * implemented yet.
416    *
417    * @return this
418    * @since 1.11.0
419    */
420   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/3982")
maxHedgedAttempts(int maxHedgedAttempts)421   public T maxHedgedAttempts(int maxHedgedAttempts) {
422     throw new UnsupportedOperationException();
423   }
424 
425   /**
426    * Sets the retry buffer size in bytes. If the buffer limit is exceeded, no RPC
427    * could retry at the moment, and in hedging case all hedges but one of the same RPC will cancel.
428    * The implementation may only estimate the buffer size being used rather than count the
429    * exact physical memory allocated. The method does not have any effect if retry is disabled by
430    * the client.
431    *
432    * <p>This method may not work as expected for the current release because retry is not fully
433    * implemented yet.
434    *
435    * @return this
436    * @since 1.10.0
437    */
438   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/3982")
retryBufferSize(long bytes)439   public T retryBufferSize(long bytes) {
440     throw new UnsupportedOperationException();
441   }
442 
443   /**
444    * Sets the per RPC buffer limit in bytes used for retry. The RPC is not retriable if its buffer
445    * limit is exceeded. The implementation may only estimate the buffer size being used rather than
446    * count the exact physical memory allocated. It does not have any effect if retry is disabled by
447    * the client.
448    *
449    * <p>This method may not work as expected for the current release because retry is not fully
450    * implemented yet.
451    *
452    * @return this
453    * @since 1.10.0
454    */
455   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/3982")
perRpcBufferLimit(long bytes)456   public T perRpcBufferLimit(long bytes) {
457     throw new UnsupportedOperationException();
458   }
459 
460 
461   /**
462    * Disables the retry and hedging subsystem provided by the gRPC library. This is designed for the
463    * case when users have their own retry implementation and want to avoid their own retry taking
464    * place simultaneously with the gRPC library layer retry.
465    *
466    * @return this
467    * @since 1.11.0
468    */
disableRetry()469   public T disableRetry() {
470     throw new UnsupportedOperationException();
471   }
472 
473   /**
474    * Enables the retry and hedging subsystem which will use
475    * <a href="https://github.com/grpc/proposal/blob/master/A6-client-retries.md#integration-with-service-config">
476    * per-method configuration</a>. If a method is unconfigured, it will be limited to
477    * transparent retries, which are safe for non-idempotent RPCs. Service config is ideally provided
478    * by the name resolver, but may also be specified via {@link #defaultServiceConfig}.
479    *
480    * @return this
481    * @since 1.11.0
482    */
enableRetry()483   public T enableRetry() {
484     throw new UnsupportedOperationException();
485   }
486 
487   /**
488    * Sets the BinaryLog object that this channel should log to. The channel does not take
489    * ownership of the object, and users are responsible for calling {@link BinaryLog#close()}.
490    *
491    * @param binaryLog the object to provide logging.
492    * @return this
493    * @since 1.13.0
494    */
495   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4017")
setBinaryLog(BinaryLog binaryLog)496   public T setBinaryLog(BinaryLog binaryLog) {
497     throw new UnsupportedOperationException();
498   }
499 
500   /**
501    * Sets the maximum number of channel trace events to keep in the tracer for each channel or
502    * subchannel. If set to 0, channel tracing is effectively disabled.
503    *
504    * @return this
505    * @since 1.13.0
506    */
507   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/4471")
maxTraceEvents(int maxTraceEvents)508   public T maxTraceEvents(int maxTraceEvents) {
509     throw new UnsupportedOperationException();
510   }
511 
512   /**
513    * Sets the proxy detector to be used in addresses name resolution. If <code>null</code> is passed
514    * the default proxy detector will be used.  For how proxies work in gRPC, please refer to the
515    * documentation on {@link ProxyDetector}.
516    *
517    * @return this
518    * @since 1.19.0
519    */
proxyDetector(ProxyDetector proxyDetector)520   public T proxyDetector(ProxyDetector proxyDetector) {
521     throw new UnsupportedOperationException();
522   }
523 
524   /**
525    * Provides a service config to the channel. The channel will use the default service config when
526    * the name resolver provides no service config or if the channel disables lookup service config
527    * from name resolver (see {@link #disableServiceConfigLookUp()}). The argument
528    * {@code serviceConfig} is a nested map representing a Json object in the most natural way:
529    *
530    *        <table border="1">
531    *          <tr>
532    *            <td>Json entry</td><td>Java Type</td>
533    *          </tr>
534    *          <tr>
535    *            <td>object</td><td>{@link Map}</td>
536    *          </tr>
537    *          <tr>
538    *            <td>array</td><td>{@link List}</td>
539    *          </tr>
540    *          <tr>
541    *            <td>string</td><td>{@link String}</td>
542    *          </tr>
543    *          <tr>
544    *            <td>number</td><td>{@link Double}</td>
545    *          </tr>
546    *          <tr>
547    *            <td>boolean</td><td>{@link Boolean}</td>
548    *          </tr>
549    *          <tr>
550    *            <td>null</td><td>{@code null}</td>
551    *          </tr>
552    *        </table>
553    *
554    * <p>If null is passed, then there will be no default service config.
555    *
556    * <p>Your preferred JSON parser may not produce results in the format expected. For such cases,
557    * you can convert its output. For example, if your parser produces Integers and other Numbers
558    * in addition to Double:
559    *
560    * <pre>{@code @SuppressWarnings("unchecked")
561    * private static Object convertNumbers(Object o) {
562    *   if (o instanceof Map) {
563    *     ((Map) o).replaceAll((k,v) -> convertNumbers(v));
564    *   } else if (o instanceof List) {
565    *     ((List) o).replaceAll(YourClass::convertNumbers);
566    *   } else if (o instanceof Number && !(o instanceof Double)) {
567    *     o = ((Number) o).doubleValue();
568    *   }
569    *   return o;
570    * }}</pre>
571    *
572    * @throws IllegalArgumentException When the given serviceConfig is invalid or the current version
573    *         of grpc library can not parse it gracefully. The state of the builder is unchanged if
574    *         an exception is thrown.
575    * @return this
576    * @since 1.20.0
577    */
578   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/5189")
defaultServiceConfig(@ullable Map<String, ?> serviceConfig)579   public T defaultServiceConfig(@Nullable Map<String, ?> serviceConfig) {
580     throw new UnsupportedOperationException();
581   }
582 
583   /**
584    * Disables service config look-up from the naming system, which is enabled by default.
585    *
586    * @return this
587    * @since 1.20.0
588    */
589   @ExperimentalApi("https://github.com/grpc/grpc-java/issues/5189")
disableServiceConfigLookUp()590   public T disableServiceConfigLookUp() {
591     throw new UnsupportedOperationException();
592   }
593 
594   /**
595    * Builds a channel using the given parameters.
596    *
597    * @since 1.0.0
598    */
build()599   public abstract ManagedChannel build();
600 
601   /**
602    * Returns the correctly typed version of the builder.
603    */
thisT()604   private T thisT() {
605     @SuppressWarnings("unchecked")
606     T thisT = (T) this;
607     return thisT;
608   }
609 }
610