From 00db638277b28d886a0b92a2593ffa3169547f65 Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Wed, 15 Apr 2026 15:42:17 -0400 Subject: [PATCH 1/7] feat: introduce Bigtable Admin V2 clients for Selective GAPIC This commit adds `BigtableTableAdminClientV2` and `BigtableInstanceAdminClientV2`, which extend the autogenerated base clients. These classes serve as the new, independent entry points for the Selective GAPIC hierarchy. For `BigtableTableAdminClientV2`, the manual wrappers for Critical User Journeys (CUJs) like `awaitOptimizeRestoredTable` and `waitForConsistency` have been relocated from the legacy client. It utilizes the new context-free ConsistencyRequest factories introduced in the previous refactoring step. For `BigtableInstanceAdminClientV2`, the class acts as a standardized entry point, as no manual overrides were required from the legacy client. b/502616786 --- .../v2/BigtableInstanceAdminClientV2.java | 49 +++++ .../admin/v2/BigtableTableAdminClientV2.java | 175 ++++++++++++++++++ .../v2/BigtableInstanceAdminClientV2Test.java | 48 +++++ .../v2/BigtableTableAdminClientV2Test.java | 155 ++++++++++++++++ 4 files changed, 427 insertions(+) create mode 100644 google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2.java create mode 100644 google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java create mode 100644 google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2Test.java create mode 100644 google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2.java new file mode 100644 index 0000000000..f8284a09c8 --- /dev/null +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2.java @@ -0,0 +1,49 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.bigtable.admin.v2; + +import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub; +import java.io.IOException; + +/** + * Modern Cloud Bigtable Instance Admin Client. + * + *

This client extends the auto-generated {@link BaseBigtableInstanceAdminClient} to provide + * manual overrides and additional convenience methods for Critical User Journeys (CUJs) that the + * GAPIC generator cannot handle natively. + */ +public class BigtableInstanceAdminClientV2 extends BaseBigtableInstanceAdminClient { + + protected BigtableInstanceAdminClientV2(BaseBigtableInstanceAdminSettings settings) + throws IOException { + super(settings); + } + + protected BigtableInstanceAdminClientV2(BigtableInstanceAdminStub stub) { + super(stub); + } + + /** Constructs an instance of BigtableInstanceAdminClientV2 with the given settings. */ + public static final BigtableInstanceAdminClientV2 createClient( + BaseBigtableInstanceAdminSettings settings) throws IOException { + return new BigtableInstanceAdminClientV2(settings); + } + + /** Constructs an instance of BigtableInstanceAdminClientV2 with the given stub. */ + public static final BigtableInstanceAdminClientV2 createClient(BigtableInstanceAdminStub stub) { + return new BigtableInstanceAdminClientV2(stub); + } +} diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java new file mode 100644 index 0000000000..75fc8972f2 --- /dev/null +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java @@ -0,0 +1,175 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.bigtable.admin.v2; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.gax.rpc.ApiExceptions; +import com.google.cloud.bigtable.admin.v2.models.ConsistencyRequest; +import com.google.cloud.bigtable.admin.v2.models.OptimizeRestoredTableOperationToken; +import com.google.cloud.bigtable.admin.v2.models.RestoredTableResult; +import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStub; +import com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub; +import com.google.common.base.Strings; +import com.google.protobuf.Empty; +import java.io.IOException; +import java.util.concurrent.ExecutionException; + +/** + * Modern Cloud Bigtable Table Admin Client. + * + *

This client extends the auto-generated {@link BaseBigtableTableAdminClient} to provide manual + * overrides and additional convenience methods for Critical User Journeys (CUJs) that the GAPIC + * generator cannot handle natively (e.g., chained Long Running Operations, Consistency Polling). + */ +public class BigtableTableAdminClientV2 extends BaseBigtableTableAdminClient { + + protected BigtableTableAdminClientV2(BaseBigtableTableAdminSettings settings) throws IOException { + super(settings); + } + + protected BigtableTableAdminClientV2(BigtableTableAdminStub stub) { + super(stub); + } + + /** Constructs an instance of BigtableTableAdminClientV2 with the given settings. */ + public static final BigtableTableAdminClientV2 createClient(BaseBigtableTableAdminSettings settings) + throws IOException { + // Explicitly create the enhanced stub + EnhancedBigtableTableAdminStub stub = + EnhancedBigtableTableAdminStub.createEnhanced( + (com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings) settings.getStubSettings()); + // Pass the enhanced stub to the existing stub-based constructor + return new BigtableTableAdminClientV2(stub); + } + + /** Constructs an instance of BigtableTableAdminClientV2 with the given stub. */ + public static final BigtableTableAdminClientV2 createClient(BigtableTableAdminStub stub) { + return new BigtableTableAdminClientV2(stub); + } + + /** + * Awaits the completion of the "Optimize Restored Table" operation. + * + *

This method blocks until the restore operation is complete, extracts the optimization token, + * and returns an ApiFuture for the optimization phase. + * + * @param restoreFuture The future returned by restoreTableAsync(). + * @return An ApiFuture that tracks the optimization progress. + */ + public ApiFuture awaitOptimizeRestoredTable(ApiFuture restoreFuture) { + // 1. Block and wait for the restore operation to complete + RestoredTableResult result; + try { + result = restoreFuture.get(); + } catch (Exception e) { + throw new RuntimeException("Restore operation failed", e); + } + + // 2. Extract the operation token from the result + // (RestoredTableResult already wraps the OptimizeRestoredTableOperationToken) + OptimizeRestoredTableOperationToken token = result.getOptimizeRestoredTableOperationToken(); + + if (token == null || Strings.isNullOrEmpty(token.getOperationName())) { + // If there is no optimization operation, return immediate success. + return ApiFutures.immediateFuture(Empty.getDefaultInstance()); + } + + // 3. Return the future for the optimization operation + return ((EnhancedBigtableTableAdminStub) getStub()).awaitOptimizeRestoredTableCallable().resumeFutureCall(token.getOperationName()); + } + + /** + * Awaits a restored table is fully optimized. + * + *

Sample code + * + *

{@code
+   * RestoredTableResult result =
+   *     client.restoreTable(RestoreTableRequest.of(clusterId, backupId).setTableId(tableId));
+   * client.awaitOptimizeRestoredTable(result.getOptimizeRestoredTableOperationToken());
+   * }
+ */ + public void awaitOptimizeRestoredTable(OptimizeRestoredTableOperationToken token) + throws ExecutionException, InterruptedException { + awaitOptimizeRestoredTableAsync(token).get(); + } + + /** + * Awaits a restored table is fully optimized asynchronously. + * + *

Sample code + * + *

{@code
+   * RestoredTableResult result =
+   *     client.restoreTable(RestoreTableRequest.of(clusterId, backupId).setTableId(tableId));
+   * ApiFuture future = client.awaitOptimizeRestoredTableAsync(
+   *     result.getOptimizeRestoredTableOperationToken());
+   *
+   * ApiFutures.addCallback(
+   *   future,
+   *   new ApiFutureCallback() {
+   *     public void onSuccess(Void unused) {
+   *       System.out.println("The optimization of the restored table is done.");
+   *     }
+   *
+   *     public void onFailure(Throwable t) {
+   *       t.printStackTrace();
+   *     }
+   *   },
+   *   MoreExecutors.directExecutor()
+   * );
+   * }
+ */ + public ApiFuture awaitOptimizeRestoredTableAsync( + OptimizeRestoredTableOperationToken token) { + ApiFuture emptyFuture = + ((EnhancedBigtableTableAdminStub) getStub()).awaitOptimizeRestoredTableCallable().resumeFutureCall(token.getOperationName()); + return ApiFutures.transform( + emptyFuture, + new com.google.api.core.ApiFunction() { + @Override + public Void apply(Empty input) { + return null; + } + }, + com.google.common.util.concurrent.MoreExecutors.directExecutor()); + } + + /** + * Polls an existing consistency token until table replication is consistent across all clusters. + * Useful for checking consistency of a token generated in a separate process. Blocks until + * completion. + * + * @param tableName The fully qualified table name to check. + * @param consistencyToken The token to poll. + */ + public void waitForConsistency(String tableName, String consistencyToken) { + ApiExceptions.callAndTranslateApiException(waitForConsistencyAsync(tableName, consistencyToken)); + } + + /** + * Asynchronously polls the consistency token. Returns a future that completes when table + * replication is consistent across all clusters. + * + * @param tableName The fully qualified table name to check. + * @param consistencyToken The token to poll. + */ + public ApiFuture waitForConsistencyAsync(String tableName, String consistencyToken) { + return ((EnhancedBigtableTableAdminStub) getStub()).awaitConsistencyCallable() + .futureCall(ConsistencyRequest.forReplicationFromTableName(tableName, consistencyToken)); + } +} diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2Test.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2Test.java new file mode 100644 index 0000000000..ef43056272 --- /dev/null +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2Test.java @@ -0,0 +1,48 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.bigtable.admin.v2; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.cloud.bigtable.admin.v2.stub.BigtableInstanceAdminStub; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mockito; + +@RunWith(JUnit4.class) +public class BigtableInstanceAdminClientV2Test { + + @Test + public void testCreateWithStub() { + BigtableInstanceAdminStub mockStub = Mockito.mock(BigtableInstanceAdminStub.class); + BigtableInstanceAdminClientV2 client = BigtableInstanceAdminClientV2.createClient(mockStub); + + assertThat(client).isNotNull(); + } + + @Test + public void testCreateClientWithSettings() throws Exception { + BaseBigtableInstanceAdminSettings settings = + BaseBigtableInstanceAdminSettings.newBuilder() + .setCredentialsProvider(com.google.api.gax.core.NoCredentialsProvider.create()) + .build(); + try (BigtableInstanceAdminClientV2 settingsClient = + BigtableInstanceAdminClientV2.createClient(settings)) { + assertThat(settingsClient).isNotNull(); + } + } +} diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java new file mode 100644 index 0000000000..1eb6c5a4ea --- /dev/null +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java @@ -0,0 +1,155 @@ +/* + * Copyright 2026 Google LLC + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.google.cloud.bigtable.admin.v2; + +import static com.google.common.truth.Truth.assertThat; + +import com.google.api.core.ApiFuture; +import com.google.api.core.ApiFutures; +import com.google.api.gax.longrunning.OperationFuture; +import com.google.api.gax.rpc.OperationCallable; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.bigtable.admin.v2.OptimizeRestoredTableMetadata; +import com.google.cloud.bigtable.admin.v2.models.ConsistencyRequest; +import com.google.cloud.bigtable.admin.v2.models.OptimizeRestoredTableOperationToken; +import com.google.cloud.bigtable.admin.v2.models.RestoredTableResult; +import com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub; +import com.google.protobuf.Empty; +import java.util.concurrent.atomic.AtomicBoolean; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; +import org.mockito.stubbing.Answer; + +@RunWith(JUnit4.class) +public class BigtableTableAdminClientV2Test { + @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule(); + + private static final String TABLE_NAME = "projects/my-project/instances/my-instance/tables/my-table"; + + @Mock private EnhancedBigtableTableAdminStub mockStub; + + @Mock + private UnaryCallable mockAwaitConsistencyCallable; + + @Mock + private OperationCallable + mockOptimizeRestoredTableCallable; + + private BigtableTableAdminClientV2 client; + + @Before + public void setUp() { + client = BigtableTableAdminClientV2.createClient(mockStub); + } + + @Test + public void testWaitForConsistencyWithToken() { + // Setup + Mockito.when(mockStub.awaitConsistencyCallable()).thenReturn(mockAwaitConsistencyCallable); + + String token = "my-token"; + ConsistencyRequest expectedRequest = ConsistencyRequest.forReplicationFromTableName(TABLE_NAME, token); + + final AtomicBoolean wasCalled = new AtomicBoolean(false); + + Mockito.when(mockAwaitConsistencyCallable.futureCall(expectedRequest)) + .thenAnswer( + (Answer>) + invocationOnMock -> { + wasCalled.set(true); + return ApiFutures.immediateFuture(null); + }); + + // Execute + client.waitForConsistency(TABLE_NAME, token); + + // Verify + assertThat(wasCalled.get()).isTrue(); + } + + @Test + public void testAwaitOptimizeRestoredTable() throws Exception { + // Setup + Mockito.when(mockStub.awaitOptimizeRestoredTableCallable()) + .thenReturn(mockOptimizeRestoredTableCallable); + + String optimizeToken = "my-optimization-token"; + + // 1. Mock the Token + OptimizeRestoredTableOperationToken mockToken = + Mockito.mock(OptimizeRestoredTableOperationToken.class); + Mockito.when(mockToken.getOperationName()).thenReturn(optimizeToken); + + // 2. Mock the Result (wrapping the token) + RestoredTableResult mockResult = Mockito.mock(RestoredTableResult.class); + Mockito.when(mockResult.getOptimizeRestoredTableOperationToken()).thenReturn(mockToken); + + // 3. Mock the Input Future (returning the result) + ApiFuture mockRestoreFuture = Mockito.mock(ApiFuture.class); + Mockito.when(mockRestoreFuture.get()).thenReturn(mockResult); + + // 4. Mock the Stub's behavior (resuming the Optimize Op) + OperationFuture mockOptimizeOp = + Mockito.mock(OperationFuture.class); + Mockito.when(mockOptimizeRestoredTableCallable.resumeFutureCall(optimizeToken)) + .thenReturn(mockOptimizeOp); + + // Execute + ApiFuture result = client.awaitOptimizeRestoredTable(mockRestoreFuture); + + // Verify + assertThat(result).isEqualTo(mockOptimizeOp); + Mockito.verify(mockOptimizeRestoredTableCallable).resumeFutureCall(optimizeToken); + } + + @Test + public void testAwaitOptimizeRestoredTable_NoOp() throws Exception { + // Setup: Result with NO optimization token (null or empty) + RestoredTableResult mockResult = Mockito.mock(RestoredTableResult.class); + Mockito.when(mockResult.getOptimizeRestoredTableOperationToken()).thenReturn(null); + + // Mock the Input Future + ApiFuture mockRestoreFuture = Mockito.mock(ApiFuture.class); + Mockito.when(mockRestoreFuture.get()).thenReturn(mockResult); + + // Execute + ApiFuture result = client.awaitOptimizeRestoredTable(mockRestoreFuture); + + // Verify: Returns immediate success (Empty) without calling the stub + assertThat(result.get()).isEqualTo(Empty.getDefaultInstance()); + } + + @Test + public void testCreateClientWithSettings() throws Exception { + BaseBigtableTableAdminSettings settings = + BaseBigtableTableAdminSettings.newBuilder() + .setCredentialsProvider(com.google.api.gax.core.NoCredentialsProvider.create()) + .build(); + try (BigtableTableAdminClientV2 settingsClient = + BigtableTableAdminClientV2.createClient(settings)) { + // Verify that the underlying stub was correctly instantiated as the Enhanced stub + // so that downcasts in the CUJs do not throw a ClassCastException. + assertThat(settingsClient.getStub()).isInstanceOf(EnhancedBigtableTableAdminStub.class); + } + } +} From ccdee5dc565602a4da9d25ae1ea563527ab405bf Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Wed, 15 Apr 2026 20:15:28 +0000 Subject: [PATCH 2/7] chore: generate libraries at Wed Apr 15 20:12:56 UTC 2026 --- .../admin/v2/BigtableTableAdminClientV2.java | 21 +++++++++----- .../admin/v2/models/ConsistencyRequest.java | 29 ++++++++++++++----- .../stub/EnhancedBigtableTableAdminStub.java | 9 ++---- .../v2/BigtableInstanceAdminClientV2Test.java | 2 +- .../v2/BigtableTableAdminClientV2Test.java | 9 +++--- 5 files changed, 45 insertions(+), 25 deletions(-) diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java index 75fc8972f2..03f0dfb49c 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java @@ -46,12 +46,13 @@ protected BigtableTableAdminClientV2(BigtableTableAdminStub stub) { } /** Constructs an instance of BigtableTableAdminClientV2 with the given settings. */ - public static final BigtableTableAdminClientV2 createClient(BaseBigtableTableAdminSettings settings) - throws IOException { + public static final BigtableTableAdminClientV2 createClient( + BaseBigtableTableAdminSettings settings) throws IOException { // Explicitly create the enhanced stub EnhancedBigtableTableAdminStub stub = EnhancedBigtableTableAdminStub.createEnhanced( - (com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings) settings.getStubSettings()); + (com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings) + settings.getStubSettings()); // Pass the enhanced stub to the existing stub-based constructor return new BigtableTableAdminClientV2(stub); } @@ -89,7 +90,9 @@ public ApiFuture awaitOptimizeRestoredTable(ApiFuture awaitOptimizeRestoredTableAsync( OptimizeRestoredTableOperationToken token) { ApiFuture emptyFuture = - ((EnhancedBigtableTableAdminStub) getStub()).awaitOptimizeRestoredTableCallable().resumeFutureCall(token.getOperationName()); + ((EnhancedBigtableTableAdminStub) getStub()) + .awaitOptimizeRestoredTableCallable() + .resumeFutureCall(token.getOperationName()); return ApiFutures.transform( emptyFuture, new com.google.api.core.ApiFunction() { @@ -158,7 +163,8 @@ public Void apply(Empty input) { * @param consistencyToken The token to poll. */ public void waitForConsistency(String tableName, String consistencyToken) { - ApiExceptions.callAndTranslateApiException(waitForConsistencyAsync(tableName, consistencyToken)); + ApiExceptions.callAndTranslateApiException( + waitForConsistencyAsync(tableName, consistencyToken)); } /** @@ -169,7 +175,8 @@ public void waitForConsistency(String tableName, String consistencyToken) { * @param consistencyToken The token to poll. */ public ApiFuture waitForConsistencyAsync(String tableName, String consistencyToken) { - return ((EnhancedBigtableTableAdminStub) getStub()).awaitConsistencyCallable() + return ((EnhancedBigtableTableAdminStub) getStub()) + .awaitConsistencyCallable() .futureCall(ConsistencyRequest.forReplicationFromTableName(tableName, consistencyToken)); } } diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/ConsistencyRequest.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/ConsistencyRequest.java index b463669603..7ed8c2d6bb 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/ConsistencyRequest.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/models/ConsistencyRequest.java @@ -61,7 +61,10 @@ public static ConsistencyRequest forReplication(String tableId, String consisten Preconditions.checkNotNull(consistencyToken, "consistencyToken must not be null"); return new AutoValue_ConsistencyRequest( - tableId, CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES, consistencyToken, false); + tableId, + CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES, + consistencyToken, + false); } public static ConsistencyRequest forDataBoost(String tableId) { @@ -76,17 +79,23 @@ public static ConsistencyRequest forReplicationFromTableName(String tableName) { } @InternalApi - public static ConsistencyRequest forReplicationFromTableName(String tableName, String consistencyToken) { + public static ConsistencyRequest forReplicationFromTableName( + String tableName, String consistencyToken) { Preconditions.checkNotNull(consistencyToken, "consistencyToken must not be null"); return new AutoValue_ConsistencyRequest( - tableName, CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES, consistencyToken, true); + tableName, + CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES, + consistencyToken, + true); } @InternalApi public CheckConsistencyRequest toCheckConsistencyProto( TableAdminRequestContext requestContext, String token) { - Preconditions.checkState(!isFullyQualified(), "Use toCheckConsistencyProto(String token) for fully qualified table names."); + Preconditions.checkState( + !isFullyQualified(), + "Use toCheckConsistencyProto(String token) for fully qualified table names."); CheckConsistencyRequest.Builder builder = CheckConsistencyRequest.newBuilder(); TableName tableName = TableName.of(requestContext.getProjectId(), requestContext.getInstanceId(), getTableId()); @@ -102,7 +111,10 @@ public CheckConsistencyRequest toCheckConsistencyProto( @InternalApi public CheckConsistencyRequest toCheckConsistencyProto(String token) { - Preconditions.checkState(isFullyQualified(), "Use toCheckConsistencyProto(TableAdminRequestContext, String) for non-qualified table names."); + Preconditions.checkState( + isFullyQualified(), + "Use toCheckConsistencyProto(TableAdminRequestContext, String) for non-qualified table" + + " names."); CheckConsistencyRequest.Builder builder = CheckConsistencyRequest.newBuilder(); if (getMode().equals(CheckConsistencyRequest.ModeCase.STANDARD_READ_REMOTE_WRITES)) { @@ -117,7 +129,8 @@ public CheckConsistencyRequest toCheckConsistencyProto(String token) { @InternalApi public GenerateConsistencyTokenRequest toGenerateTokenProto( TableAdminRequestContext requestContext) { - Preconditions.checkState(!isFullyQualified(), "Use toGenerateTokenProto() for fully qualified table names."); + Preconditions.checkState( + !isFullyQualified(), "Use toGenerateTokenProto() for fully qualified table names."); GenerateConsistencyTokenRequest.Builder builder = GenerateConsistencyTokenRequest.newBuilder(); TableName tableName = TableName.of(requestContext.getProjectId(), requestContext.getInstanceId(), getTableId()); @@ -127,7 +140,9 @@ public GenerateConsistencyTokenRequest toGenerateTokenProto( @InternalApi public GenerateConsistencyTokenRequest toGenerateTokenProto() { - Preconditions.checkState(isFullyQualified(), "Use toGenerateTokenProto(TableAdminRequestContext) for non-qualified table names."); + Preconditions.checkState( + isFullyQualified(), + "Use toGenerateTokenProto(TableAdminRequestContext) for non-qualified table names."); GenerateConsistencyTokenRequest.Builder builder = GenerateConsistencyTokenRequest.newBuilder(); return builder.setName(getTableId()).build(); } diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/EnhancedBigtableTableAdminStub.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/EnhancedBigtableTableAdminStub.java index 79da312d37..3333529b3b 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/EnhancedBigtableTableAdminStub.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/EnhancedBigtableTableAdminStub.java @@ -54,8 +54,7 @@ public class EnhancedBigtableTableAdminStub extends GrpcBigtableTableAdminStub { private final BigtableTableAdminStubSettings settings; private final ClientContext clientContext; - @javax.annotation.Nullable - private final TableAdminRequestContext requestContext; + @javax.annotation.Nullable private final TableAdminRequestContext requestContext; @Deprecated private final AwaitReplicationCallable awaitReplicationCallable; @@ -64,10 +63,8 @@ public class EnhancedBigtableTableAdminStub extends GrpcBigtableTableAdminStub { optimizeRestoredTableOperationBaseCallable; public static EnhancedBigtableTableAdminStub createEnhanced( - BigtableTableAdminStubSettings settings) - throws IOException { - return new EnhancedBigtableTableAdminStub( - settings, ClientContext.create(settings), null); + BigtableTableAdminStubSettings settings) throws IOException { + return new EnhancedBigtableTableAdminStub(settings, ClientContext.create(settings), null); } public static EnhancedBigtableTableAdminStub createEnhanced( diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2Test.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2Test.java index ef43056272..7abf4941a6 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2Test.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableInstanceAdminClientV2Test.java @@ -30,7 +30,7 @@ public class BigtableInstanceAdminClientV2Test { public void testCreateWithStub() { BigtableInstanceAdminStub mockStub = Mockito.mock(BigtableInstanceAdminStub.class); BigtableInstanceAdminClientV2 client = BigtableInstanceAdminClientV2.createClient(mockStub); - + assertThat(client).isNotNull(); } diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java index 1eb6c5a4ea..4f7a3fcb0b 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java @@ -44,12 +44,12 @@ public class BigtableTableAdminClientV2Test { @Rule public final MockitoRule mockitoRule = MockitoJUnit.rule(); - private static final String TABLE_NAME = "projects/my-project/instances/my-instance/tables/my-table"; + private static final String TABLE_NAME = + "projects/my-project/instances/my-instance/tables/my-table"; @Mock private EnhancedBigtableTableAdminStub mockStub; - @Mock - private UnaryCallable mockAwaitConsistencyCallable; + @Mock private UnaryCallable mockAwaitConsistencyCallable; @Mock private OperationCallable @@ -68,7 +68,8 @@ public void testWaitForConsistencyWithToken() { Mockito.when(mockStub.awaitConsistencyCallable()).thenReturn(mockAwaitConsistencyCallable); String token = "my-token"; - ConsistencyRequest expectedRequest = ConsistencyRequest.forReplicationFromTableName(TABLE_NAME, token); + ConsistencyRequest expectedRequest = + ConsistencyRequest.forReplicationFromTableName(TABLE_NAME, token); final AtomicBoolean wasCalled = new AtomicBoolean(false); From bff60a6d403da773c88642d23be9672bfa9c131e Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 17 Apr 2026 10:54:10 -0400 Subject: [PATCH 3/7] PR feedback --- .../admin/v2/BigtableTableAdminClientV2.java | 184 ++++++++++++++++-- .../v2/stub/AwaitConsistencyCallable.java | 6 +- .../v2/BigtableTableAdminClientV2Test.java | 6 +- 3 files changed, 174 insertions(+), 22 deletions(-) diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java index 03f0dfb49c..fa61757095 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java @@ -15,18 +15,40 @@ */ package com.google.cloud.bigtable.admin.v2; +import com.google.api.core.ApiFunction; import com.google.api.core.ApiFuture; import com.google.api.core.ApiFutures; +import com.google.api.gax.grpc.GrpcCallSettings; +import com.google.api.gax.grpc.GrpcCallableFactory; +import com.google.api.gax.grpc.ProtoOperationTransformers.MetadataTransformer; +import com.google.api.gax.grpc.ProtoOperationTransformers.ResponseTransformer; +import com.google.api.gax.longrunning.OperationSnapshot; +import com.google.api.gax.longrunning.OperationTimedPollAlgorithm; +import com.google.api.gax.retrying.RetrySettings; import com.google.api.gax.rpc.ApiExceptions; +import com.google.api.gax.rpc.ClientContext; +import com.google.api.gax.rpc.OperationCallSettings; +import com.google.api.gax.rpc.OperationCallable; +import com.google.api.gax.rpc.UnaryCallSettings; +import com.google.api.gax.rpc.UnaryCallable; +import com.google.bigtable.admin.v2.OptimizeRestoredTableMetadata; import com.google.cloud.bigtable.admin.v2.models.ConsistencyRequest; import com.google.cloud.bigtable.admin.v2.models.OptimizeRestoredTableOperationToken; import com.google.cloud.bigtable.admin.v2.models.RestoredTableResult; +import com.google.cloud.bigtable.admin.v2.stub.AwaitConsistencyCallable; import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStub; -import com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub; +import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings; import com.google.common.base.Strings; +import com.google.common.util.concurrent.MoreExecutors; +import com.google.longrunning.Operation; import com.google.protobuf.Empty; +import io.grpc.MethodDescriptor; +import io.grpc.MethodDescriptor.Marshaller; +import io.grpc.MethodDescriptor.MethodType; import java.io.IOException; +import java.io.InputStream; import java.util.concurrent.ExecutionException; +import org.threeten.bp.Duration; /** * Modern Cloud Bigtable Table Admin Client. @@ -36,25 +58,135 @@ * generator cannot handle natively (e.g., chained Long Running Operations, Consistency Polling). */ public class BigtableTableAdminClientV2 extends BaseBigtableTableAdminClient { + private final AwaitConsistencyCallable awaitConsistencyCallable; + private final OperationCallable + optimizeRestoredTableOperationBaseCallable; protected BigtableTableAdminClientV2(BaseBigtableTableAdminSettings settings) throws IOException { super(settings); + this.awaitConsistencyCallable = + createAwaitConsistencyCallable((BigtableTableAdminStubSettings) settings.getStubSettings()); + this.optimizeRestoredTableOperationBaseCallable = + createOptimizeRestoredTableOperationBaseCallable( + (BigtableTableAdminStubSettings) settings.getStubSettings()); } protected BigtableTableAdminClientV2(BigtableTableAdminStub stub) { super(stub); + this.awaitConsistencyCallable = null; + this.optimizeRestoredTableOperationBaseCallable = null; + } + + private AwaitConsistencyCallable createAwaitConsistencyCallable( + BigtableTableAdminStubSettings settings) throws IOException { + ClientContext clientContext = ClientContext.create(settings); + // TODO(igorbernstein2): expose polling settings + RetrySettings pollingSettings = + RetrySettings.newBuilder() + .setTotalTimeout( + settings.checkConsistencySettings().getRetrySettings().getTotalTimeout()) + .setInitialRetryDelay(Duration.ofSeconds(10)) + .setRetryDelayMultiplier(1.0) + .setMaxRetryDelay(Duration.ofSeconds(10)) + .setInitialRpcTimeout(Duration.ZERO) + .setMaxRpcTimeout(Duration.ZERO) + .setRpcTimeoutMultiplier(1.0) + .build(); + + return AwaitConsistencyCallable.create( + getStub().generateConsistencyTokenCallable(), + getStub().checkConsistencyCallable(), + clientContext, + pollingSettings); + } + + private OperationCallable + createOptimizeRestoredTableOperationBaseCallable(BigtableTableAdminStubSettings settings) + throws IOException { + ClientContext clientContext = ClientContext.create(settings); + + GrpcCallSettings unusedInitialCallSettings = + GrpcCallSettings.create( + MethodDescriptor.newBuilder() + .setType(MethodType.UNARY) + .setFullMethodName( + "google.bigtable.admin.v2.BigtableTableAdmin/OptimizeRestoredTable") + .setRequestMarshaller( + new Marshaller() { + @Override + public InputStream stream(Void value) { + throw new UnsupportedOperationException("not used"); + } + + @Override + public Void parse(InputStream stream) { + throw new UnsupportedOperationException("not used"); + } + }) + .setResponseMarshaller( + new Marshaller() { + @Override + public InputStream stream(Operation value) { + throw new UnsupportedOperationException("not used"); + } + + @Override + public Operation parse(InputStream stream) { + throw new UnsupportedOperationException("not used"); + } + }) + .build()); + + final MetadataTransformer protoMetadataTransformer = + MetadataTransformer.create(OptimizeRestoredTableMetadata.class); + + final ResponseTransformer protoResponseTransformer = + ResponseTransformer.create(com.google.protobuf.Empty.class); + + OperationCallSettings operationCallSettings = + OperationCallSettings.newBuilder() + .setInitialCallSettings( + UnaryCallSettings.newUnaryCallSettingsBuilder() + .setSimpleTimeoutNoRetries(Duration.ZERO) + .build()) + .setMetadataTransformer( + new ApiFunction() { + @Override + public OptimizeRestoredTableMetadata apply(OperationSnapshot input) { + return protoMetadataTransformer.apply(input); + } + }) + .setResponseTransformer( + new ApiFunction() { + @Override + public Empty apply(OperationSnapshot input) { + return protoResponseTransformer.apply(input); + } + }) + .setPollingAlgorithm( + OperationTimedPollAlgorithm.create( + RetrySettings.newBuilder() + .setInitialRetryDelay(Duration.ofMillis(500L)) + .setRetryDelayMultiplier(1.5) + .setMaxRetryDelay(Duration.ofMillis(5000L)) + .setInitialRpcTimeout(Duration.ZERO) + .setRpcTimeoutMultiplier(1.0) + .setMaxRpcTimeout(Duration.ZERO) + .setTotalTimeout(Duration.ofMillis(600000L)) + .build())) + .build(); + + return GrpcCallableFactory.createOperationCallable( + unusedInitialCallSettings, + operationCallSettings, + clientContext, + getStub().getOperationsStub()); } /** Constructs an instance of BigtableTableAdminClientV2 with the given settings. */ public static final BigtableTableAdminClientV2 createClient( BaseBigtableTableAdminSettings settings) throws IOException { - // Explicitly create the enhanced stub - EnhancedBigtableTableAdminStub stub = - EnhancedBigtableTableAdminStub.createEnhanced( - (com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings) - settings.getStubSettings()); - // Pass the enhanced stub to the existing stub-based constructor - return new BigtableTableAdminClientV2(stub); + return new BigtableTableAdminClientV2(settings); } /** Constructs an instance of BigtableTableAdminClientV2 with the given stub. */ @@ -90,9 +222,7 @@ public ApiFuture awaitOptimizeRestoredTable(ApiFuture awaitOptimizeRestoredTableAsync( OptimizeRestoredTableOperationToken token) { ApiFuture emptyFuture = - ((EnhancedBigtableTableAdminStub) getStub()) - .awaitOptimizeRestoredTableCallable() - .resumeFutureCall(token.getOperationName()); + getOptimizeRestoredTableCallable().resumeFutureCall(token.getOperationName()); return ApiFutures.transform( emptyFuture, new com.google.api.core.ApiFunction() { @@ -175,8 +303,32 @@ public void waitForConsistency(String tableName, String consistencyToken) { * @param consistencyToken The token to poll. */ public ApiFuture waitForConsistencyAsync(String tableName, String consistencyToken) { - return ((EnhancedBigtableTableAdminStub) getStub()) - .awaitConsistencyCallable() + return getAwaitConsistencyCallable() .futureCall(ConsistencyRequest.forReplicationFromTableName(tableName, consistencyToken)); } + + private UnaryCallable getAwaitConsistencyCallable() { + if (awaitConsistencyCallable != null) { + return awaitConsistencyCallable; + } + // Fallback for tests or stub-based initialization + if (getStub() instanceof com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) { + return ((com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) getStub()) + .awaitConsistencyCallable(); + } + throw new IllegalStateException("AwaitConsistencyCallable not initialized."); + } + + private OperationCallable + getOptimizeRestoredTableCallable() { + if (optimizeRestoredTableOperationBaseCallable != null) { + return optimizeRestoredTableOperationBaseCallable; + } + // Fallback for tests or stub-based initialization + if (getStub() instanceof com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) { + return ((com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) getStub()) + .awaitOptimizeRestoredTableCallable(); + } + throw new IllegalStateException("OptimizeRestoredTableCallable not initialized."); + } } diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/AwaitConsistencyCallable.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/AwaitConsistencyCallable.java index a8ccdd9704..f772421b8d 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/AwaitConsistencyCallable.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/stub/AwaitConsistencyCallable.java @@ -51,7 +51,7 @@ *

This callable wraps GenerateConsistencyToken and CheckConsistency RPCs. It will generate a * token then poll until isConsistent is true. */ -class AwaitConsistencyCallable extends UnaryCallable { +public class AwaitConsistencyCallable extends UnaryCallable { private final UnaryCallable generateCallable; private final UnaryCallable checkCallable; @@ -59,7 +59,7 @@ class AwaitConsistencyCallable extends UnaryCallable { @Nullable private final TableAdminRequestContext requestContext; - static AwaitConsistencyCallable create( + public static AwaitConsistencyCallable create( UnaryCallable generateCallable, UnaryCallable checkCallable, @@ -79,7 +79,7 @@ static AwaitConsistencyCallable create( generateCallable, checkCallable, retryingExecutor, requestContext); } - static AwaitConsistencyCallable create( + public static AwaitConsistencyCallable create( UnaryCallable generateCallable, UnaryCallable checkCallable, diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java index 4f7a3fcb0b..0334f72201 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java @@ -148,9 +148,9 @@ public void testCreateClientWithSettings() throws Exception { .build(); try (BigtableTableAdminClientV2 settingsClient = BigtableTableAdminClientV2.createClient(settings)) { - // Verify that the underlying stub was correctly instantiated as the Enhanced stub - // so that downcasts in the CUJs do not throw a ClassCastException. - assertThat(settingsClient.getStub()).isInstanceOf(EnhancedBigtableTableAdminStub.class); + // Verify that the underlying stub is NOT an Enhanced stub by default + // but the client has successfully initialized its own callables. + assertThat(settingsClient.getStub()).isNotInstanceOf(EnhancedBigtableTableAdminStub.class); } } } From d3688251e19d528c290ab47e390c230f42550f04 Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Fri, 17 Apr 2026 14:58:36 +0000 Subject: [PATCH 4/7] chore: generate libraries at Fri Apr 17 14:55:58 UTC 2026 --- .../bigtable/admin/v2/BigtableTableAdminClientV2.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java index fa61757095..7749b3ca3f 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java @@ -39,7 +39,6 @@ import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStub; import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStubSettings; import com.google.common.base.Strings; -import com.google.common.util.concurrent.MoreExecutors; import com.google.longrunning.Operation; import com.google.protobuf.Empty; import io.grpc.MethodDescriptor; @@ -312,7 +311,8 @@ private UnaryCallable getAwaitConsistencyCallable() { return awaitConsistencyCallable; } // Fallback for tests or stub-based initialization - if (getStub() instanceof com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) { + if (getStub() + instanceof com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) { return ((com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) getStub()) .awaitConsistencyCallable(); } @@ -325,7 +325,8 @@ private UnaryCallable getAwaitConsistencyCallable() { return optimizeRestoredTableOperationBaseCallable; } // Fallback for tests or stub-based initialization - if (getStub() instanceof com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) { + if (getStub() + instanceof com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) { return ((com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) getStub()) .awaitOptimizeRestoredTableCallable(); } From 392717f18a22f3aaeeaca1ce2ff931e4606007ef Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 17 Apr 2026 12:30:41 -0400 Subject: [PATCH 5/7] PR comment 2 --- .../admin/v2/BigtableTableAdminClientV2.java | 21 ++++++++++++------- .../v2/BigtableTableAdminClientV2Test.java | 13 ++++++------ 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java index 7749b3ca3f..52b439a01d 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java @@ -76,6 +76,17 @@ protected BigtableTableAdminClientV2(BigtableTableAdminStub stub) { this.optimizeRestoredTableOperationBaseCallable = null; } + @com.google.common.annotations.VisibleForTesting + BigtableTableAdminClientV2( + BigtableTableAdminStub stub, + AwaitConsistencyCallable awaitConsistencyCallable, + OperationCallable + optimizeRestoredTableOperationBaseCallable) { + super(stub); + this.awaitConsistencyCallable = awaitConsistencyCallable; + this.optimizeRestoredTableOperationBaseCallable = optimizeRestoredTableOperationBaseCallable; + } + private AwaitConsistencyCallable createAwaitConsistencyCallable( BigtableTableAdminStubSettings settings) throws IOException { ClientContext clientContext = ClientContext.create(settings); @@ -324,12 +335,8 @@ private UnaryCallable getAwaitConsistencyCallable() { if (optimizeRestoredTableOperationBaseCallable != null) { return optimizeRestoredTableOperationBaseCallable; } - // Fallback for tests or stub-based initialization - if (getStub() - instanceof com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) { - return ((com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) getStub()) - .awaitOptimizeRestoredTableCallable(); - } - throw new IllegalStateException("OptimizeRestoredTableCallable not initialized."); + throw new IllegalStateException( + "OptimizeRestoredTableCallable not initialized. BigtableTableAdminClientV2 must be " + + "initialized via settings to use this functionality."); } } diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java index 0334f72201..a8d919e1e3 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java @@ -26,6 +26,8 @@ import com.google.cloud.bigtable.admin.v2.models.ConsistencyRequest; import com.google.cloud.bigtable.admin.v2.models.OptimizeRestoredTableOperationToken; import com.google.cloud.bigtable.admin.v2.models.RestoredTableResult; +import com.google.cloud.bigtable.admin.v2.stub.AwaitConsistencyCallable; +import com.google.cloud.bigtable.admin.v2.stub.BigtableTableAdminStub; import com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub; import com.google.protobuf.Empty; import java.util.concurrent.atomic.AtomicBoolean; @@ -47,9 +49,9 @@ public class BigtableTableAdminClientV2Test { private static final String TABLE_NAME = "projects/my-project/instances/my-instance/tables/my-table"; - @Mock private EnhancedBigtableTableAdminStub mockStub; + @Mock private BigtableTableAdminStub mockStub; - @Mock private UnaryCallable mockAwaitConsistencyCallable; + @Mock private AwaitConsistencyCallable mockAwaitConsistencyCallable; @Mock private OperationCallable @@ -59,13 +61,14 @@ public class BigtableTableAdminClientV2Test { @Before public void setUp() { - client = BigtableTableAdminClientV2.createClient(mockStub); + client = + new BigtableTableAdminClientV2( + mockStub, mockAwaitConsistencyCallable, mockOptimizeRestoredTableCallable); } @Test public void testWaitForConsistencyWithToken() { // Setup - Mockito.when(mockStub.awaitConsistencyCallable()).thenReturn(mockAwaitConsistencyCallable); String token = "my-token"; ConsistencyRequest expectedRequest = @@ -91,8 +94,6 @@ public void testWaitForConsistencyWithToken() { @Test public void testAwaitOptimizeRestoredTable() throws Exception { // Setup - Mockito.when(mockStub.awaitOptimizeRestoredTableCallable()) - .thenReturn(mockOptimizeRestoredTableCallable); String optimizeToken = "my-optimization-token"; From ed4476a09476b610e409f9c01bf0ec09bcaf83af Mon Sep 17 00:00:00 2001 From: cloud-java-bot Date: Fri, 17 Apr 2026 16:34:31 +0000 Subject: [PATCH 6/7] chore: generate libraries at Fri Apr 17 16:31:54 UTC 2026 --- .../cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java | 1 - 1 file changed, 1 deletion(-) diff --git a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java index a8d919e1e3..104088d2b3 100644 --- a/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java +++ b/google-cloud-bigtable/src/test/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2Test.java @@ -21,7 +21,6 @@ import com.google.api.core.ApiFutures; import com.google.api.gax.longrunning.OperationFuture; import com.google.api.gax.rpc.OperationCallable; -import com.google.api.gax.rpc.UnaryCallable; import com.google.bigtable.admin.v2.OptimizeRestoredTableMetadata; import com.google.cloud.bigtable.admin.v2.models.ConsistencyRequest; import com.google.cloud.bigtable.admin.v2.models.OptimizeRestoredTableOperationToken; From 95f4d32dcd6151dbbc6fb0af649f0f9ceebc011a Mon Sep 17 00:00:00 2001 From: Jin Seop Kim Date: Fri, 17 Apr 2026 12:47:06 -0400 Subject: [PATCH 7/7] PR feedback 3 --- .../bigtable/admin/v2/BigtableTableAdminClientV2.java | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java index 52b439a01d..f61f2f0904 100644 --- a/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java +++ b/google-cloud-bigtable/src/main/java/com/google/cloud/bigtable/admin/v2/BigtableTableAdminClientV2.java @@ -321,13 +321,9 @@ private UnaryCallable getAwaitConsistencyCallable() { if (awaitConsistencyCallable != null) { return awaitConsistencyCallable; } - // Fallback for tests or stub-based initialization - if (getStub() - instanceof com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) { - return ((com.google.cloud.bigtable.admin.v2.stub.EnhancedBigtableTableAdminStub) getStub()) - .awaitConsistencyCallable(); - } - throw new IllegalStateException("AwaitConsistencyCallable not initialized."); + throw new IllegalStateException( + "AwaitConsistencyCallable not initialized. BigtableTableAdminClientV2 must be " + + "initialized via settings to use this functionality."); } private OperationCallable