@@ -39,8 +39,14 @@ public class ServiceStubsOptions {
3939
4040 protected final @ Nullable Consumer <ManagedChannelBuilder <?>> channelInitializer ;
4141
42- /** Indicates whether basic HTTPS/SSL/TLS should be enabled * */
43- protected final boolean enableHttps ;
42+ /**
43+ * Indicates whether basic HTTPS/SSL/TLS should be enabled. Null means not explicitly set by the
44+ * user, allowing runtime derivation of the effective value.
45+ */
46+ protected final Boolean enableHttps ;
47+
48+ /** Indicates whether an API key was provided, used for automatic TLS enablement */
49+ protected final boolean apiKeyProvided ;
4450
4551 /** The user provided context for SSL/TLS over gRPC * */
4652 protected final SslContext sslContext ;
@@ -113,6 +119,7 @@ public class ServiceStubsOptions {
113119 this .target = that .target ;
114120 this .channelInitializer = that .channelInitializer ;
115121 this .enableHttps = that .enableHttps ;
122+ this .apiKeyProvided = that .apiKeyProvided ;
116123 this .sslContext = that .sslContext ;
117124 this .healthCheckAttemptTimeout = that .healthCheckAttemptTimeout ;
118125 this .systemInfoTimeout = that .systemInfoTimeout ;
@@ -134,7 +141,8 @@ public class ServiceStubsOptions {
134141 ManagedChannel channel ,
135142 String target ,
136143 @ Nullable Consumer <ManagedChannelBuilder <?>> channelInitializer ,
137- boolean enableHttps ,
144+ Boolean enableHttps ,
145+ boolean apiKeyProvided ,
138146 SslContext sslContext ,
139147 Duration healthCheckAttemptTimeout ,
140148 Duration healthCheckTimeout ,
@@ -154,6 +162,7 @@ public class ServiceStubsOptions {
154162 this .target = target ;
155163 this .channelInitializer = channelInitializer ;
156164 this .enableHttps = enableHttps ;
165+ this .apiKeyProvided = apiKeyProvided ;
157166 this .sslContext = sslContext ;
158167 this .healthCheckAttemptTimeout = healthCheckAttemptTimeout ;
159168 this .healthCheckTimeout = healthCheckTimeout ;
@@ -202,11 +211,24 @@ public Consumer<ManagedChannelBuilder<?>> getChannelInitializer() {
202211 }
203212
204213 /**
205- * @return if gRPC should use SSL/TLS; Ignored and assumed {@code true} if {@link
206- * #getSslContext()} is set
214+ * Returns whether gRPC should use SSL/TLS. This method computes the effective value based on:
215+ *
216+ * <ul>
217+ * <li>If explicitly set via {@link Builder#setEnableHttps(boolean)}, returns that value
218+ * <li>If an API key was provided and no custom SSL context or channel is set, returns {@code
219+ * true} (auto-enabled)
220+ * <li>Otherwise returns {@code false}
221+ * </ul>
222+ *
223+ * <p>Note: When {@link #getSslContext()} is set, TLS is handled by the SSL context regardless of
224+ * this value.
225+ *
226+ * @return if gRPC should use SSL/TLS
207227 */
208228 public boolean getEnableHttps () {
209- return enableHttps ;
229+ return (enableHttps != null )
230+ ? enableHttps
231+ : (apiKeyProvided && sslContext == null && channel == null );
210232 }
211233
212234 /**
@@ -325,12 +347,13 @@ public boolean equals(Object o) {
325347 if (this == o ) return true ;
326348 if (o == null || getClass () != o .getClass ()) return false ;
327349 ServiceStubsOptions that = (ServiceStubsOptions ) o ;
328- return enableHttps == that .enableHttps
350+ return apiKeyProvided == that .apiKeyProvided
329351 && enableKeepAlive == that .enableKeepAlive
330352 && keepAlivePermitWithoutStream == that .keepAlivePermitWithoutStream
331353 && Objects .equals (channel , that .channel )
332354 && Objects .equals (target , that .target )
333355 && Objects .equals (channelInitializer , that .channelInitializer )
356+ && Objects .equals (enableHttps , that .enableHttps )
334357 && Objects .equals (sslContext , that .sslContext )
335358 && Objects .equals (healthCheckAttemptTimeout , that .healthCheckAttemptTimeout )
336359 && Objects .equals (healthCheckTimeout , that .healthCheckTimeout )
@@ -353,6 +376,7 @@ public int hashCode() {
353376 target ,
354377 channelInitializer ,
355378 enableHttps ,
379+ apiKeyProvided ,
356380 sslContext ,
357381 healthCheckAttemptTimeout ,
358382 healthCheckTimeout ,
@@ -444,6 +468,7 @@ protected Builder(ServiceStubsOptions options) {
444468 this .target = options .target ;
445469 this .channelInitializer = options .channelInitializer ;
446470 this .enableHttps = options .enableHttps ;
471+ this .apiKeyProvided = options .apiKeyProvided ;
447472 this .sslContext = options .sslContext ;
448473 this .healthCheckAttemptTimeout = options .healthCheckAttemptTimeout ;
449474 this .healthCheckTimeout = options .healthCheckTimeout ;
@@ -456,8 +481,15 @@ protected Builder(ServiceStubsOptions options) {
456481 this .connectionBackoffResetFrequency = options .connectionBackoffResetFrequency ;
457482 this .grpcReconnectFrequency = options .grpcReconnectFrequency ;
458483 this .headers = options .headers ;
459- this .grpcMetadataProviders = options .grpcMetadataProviders ;
460- this .grpcClientInterceptors = options .grpcClientInterceptors ;
484+ // Make mutable copies of collections to allow adding more items
485+ this .grpcMetadataProviders =
486+ options .grpcMetadataProviders != null && !options .grpcMetadataProviders .isEmpty ()
487+ ? new ArrayList <>(options .grpcMetadataProviders )
488+ : null ;
489+ this .grpcClientInterceptors =
490+ options .grpcClientInterceptors != null && !options .grpcClientInterceptors .isEmpty ()
491+ ? new ArrayList <>(options .grpcClientInterceptors )
492+ : null ;
461493 this .metricsScope = options .metricsScope ;
462494 }
463495
@@ -805,7 +837,8 @@ public ServiceStubsOptions build() {
805837 this .channel ,
806838 this .target ,
807839 this .channelInitializer ,
808- this .enableHttps != null ? this .enableHttps : false ,
840+ this .enableHttps ,
841+ this .apiKeyProvided ,
809842 this .sslContext ,
810843 this .healthCheckAttemptTimeout ,
811844 this .healthCheckTimeout ,
@@ -853,14 +886,6 @@ public ServiceStubsOptions validateAndBuildWithDefaults() {
853886 Collection <ClientInterceptor > grpcClientInterceptors =
854887 MoreObjects .firstNonNull (this .grpcClientInterceptors , Collections .emptyList ());
855888
856- // Resolve enableHttps: explicit value, auto-enable with API key, or default false
857- boolean enableHttps = false ;
858- if (this .enableHttps != null ) {
859- enableHttps = this .enableHttps ;
860- } else if (this .apiKeyProvided && this .sslContext == null && this .channel == null ) {
861- enableHttps = true ;
862- }
863-
864889 Scope metricsScope = this .metricsScope != null ? this .metricsScope : new NoopScope ();
865890 Duration healthCheckAttemptTimeout =
866891 this .healthCheckAttemptTimeout != null
@@ -875,7 +900,8 @@ public ServiceStubsOptions validateAndBuildWithDefaults() {
875900 this .channel ,
876901 target ,
877902 this .channelInitializer ,
878- enableHttps ,
903+ this .enableHttps ,
904+ this .apiKeyProvided ,
879905 this .sslContext ,
880906 healthCheckAttemptTimeout ,
881907 healthCheckTimeout ,
0 commit comments