Repository: GoogleCloudPlatform/cloud-bigtable-client
Pull request #2007 (2018-11-21 16:41:36)

mutateRow method implemented
`IBigtableDataClient` interface - `mutateRow` method implemented


Patch:
diff --git a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableDataClientWrapper.java b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableDataClientWrapper.java
new file mode 100644
index 000000000..ddf1314ef
--- /dev/null
+++ b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableDataClientWrapper.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2018 Google LLC.  All Rights Reserved.
+ *
+ * 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.grpc;
+
+import com.google.api.core.ApiFuture;
+import com.google.bigtable.v2.MutateRowRequest;
+import com.google.cloud.bigtable.config.BigtableOptions;
+import com.google.cloud.bigtable.core.IBigtableDataClient;
+import com.google.cloud.bigtable.core.IBulkMutation;
+import com.google.cloud.bigtable.data.v2.internal.RequestContext;
+import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation;
+import com.google.cloud.bigtable.data.v2.models.InstanceName;
+import com.google.cloud.bigtable.data.v2.models.ReadModifyWriteRow;
+import com.google.cloud.bigtable.data.v2.models.Row;
+import com.google.cloud.bigtable.data.v2.models.RowMutation;
+
+/**
+ * This class implements the {@link IBigtableDataClient} interface which provides access to google cloud
+ * java
+ */
+public class BigtableDataClientWrapper implements IBigtableDataClient {
+
+  private final BigtableDataClient delegate;
+  private final RequestContext requestContext;
+
+  public BigtableDataClientWrapper(BigtableDataClient bigtableDataClient,
+      BigtableOptions options) {
+    this.delegate = bigtableDataClient;
+    this.requestContext = RequestContext
+        .create(InstanceName.of(options.getProjectId(),
+            options.getInstanceId()),
+            options.getAppProfileId()
+        );
+  }
+
+  @Override
+  public void mutateRow(RowMutation rowMutation) {
+    MutateRowRequest mutateRowRequest = rowMutation.toProto(requestContext);
+    delegate.mutateRow(mutateRowRequest);
+  }
+
+  @Override
+  public ApiFuture<Void> mutateRowAsync(RowMutation rowMutation) {
+    throw new UnsupportedOperationException("Not implemented yet");
+  }
+
+  @Override
+  public Row readModifyWriteRow(ReadModifyWriteRow readModifyWriteRow) {
+    throw new UnsupportedOperationException("Not implemented yet");
+  }
+
+  @Override
+  public ApiFuture<Row> readModifyWriteRowAsync(ReadModifyWriteRow readModifyWriteRow) {
+    throw new UnsupportedOperationException("Not implemented yet");
+  }
+
+  @Override
+  public IBulkMutation createBulkMutationBatcher() {
+    throw new UnsupportedOperationException("Not implemented yet");
+  }
+
+  @Override
+  public ApiFuture<Boolean> checkAndMutateRowAsync(ConditionalRowMutation conditionalRowMutation) {
+    throw new UnsupportedOperationException("Not implemented yet");
+  }
+
+  @Override
+  public Boolean checkAndMutateRow(ConditionalRowMutation conditionalRowMutation) {
+    throw new UnsupportedOperationException("Not implemented yet");
+  }
+}
diff --git a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableDataGrpcClient.java b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableDataGrpcClient.java
index c7835264f..a8ec3fee3 100644
--- a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableDataGrpcClient.java
+++ b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableDataGrpcClient.java
@@ -19,6 +19,7 @@ import static com.google.cloud.bigtable.grpc.io.GoogleCloudResourcePrefixInterce
 
 import com.google.api.core.ApiClock;
 import com.google.api.core.NanoClock;
+import com.google.common.util.concurrent.MoreExecutors;
 import io.grpc.CallOptions;
 import io.grpc.Channel;
 import io.grpc.Metadata;
@@ -27,6 +28,7 @@ import io.grpc.stub.StreamObserver;
 
 import java.io.IOException;
 import java.util.List;
+import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import javax.annotation.Nullable;
 import com.google.bigtable.v2.BigtableGrpc;
@@ -350,7 +352,7 @@ public class BigtableDataGrpcClient implements BigtableDataClient {
 
     return Futures.transform(
         createStreamingListener(request, readRowsAsync, request.getTableName()).getAsyncResult(),
-        ROW_LIST_TRANSFORMER);
+        ROW_LIST_TRANSFORMER, MoreExecutors.directExecutor());
   }
 
   /** {@inheritDoc} */
@@ -362,7 +364,7 @@ public class BigtableDataGrpcClient implements BigtableDataClient {
 
     return Futures.transform(
         createStreamingListener(request, readRowsAsync, request.getTableName()).getAsyncResult(),
-        FLAT_ROW_LIST_TRANSFORMER);
+        FLAT_ROW_LIST_TRANSFORMER, MoreExecutors.directExecutor());
   }
 
   /** {@inheritDoc} */
diff --git a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableInstanceName.java b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableInstanceName.java
index df68c8f57..ce58eafc4 100644
--- a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableInstanceName.java
+++ b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableInstanceName.java
@@ -126,6 +126,11 @@ public class BigtableInstanceName implements Serializable {
     return InstanceName.of(projectId, instanceId);
   }
 
+  //TODO(rahulkql): Refactor once google-cloud-java/issues/4091 is resolved.
+  public com.google.bigtable.admin.v2.InstanceName toAdminInstanceName() {
+    return com.google.bigtable.admin.v2.InstanceName.of(projectId, instanceId);
+  }
+
   public BigtableClusterName toClusterName(String clusterId) {
     return new BigtableClusterName(instanceName + "/clusters/" + clusterId);
   }
diff --git a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableSession.java b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableSession.java
index 325666089..69480d5d5 100644
--- a/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableSession.java
+++ b/bigtable-client-core-parent/bigtable-client-core/src/main/java/com/google/cloud/bigtable/grpc/BigtableSession.java
@@ -26,6 +26,7 @@ import com.google.cloud.bigtable.config.BulkOptions;
 import com.google.cloud.bigtable.config.CredentialOptions;
 import com.google.cloud.bigtable.config.Logger;
 import com.google.cloud.bigtable.config.RetryOptions;
+import com.google.cloud.bigtable.core.IBigtableDataClient;
 import com.google.cloud.bigtable.grpc.async.AsyncExecutor;
 import com.google.cloud.bigtable.grpc.async.BulkMutation;
 import com.google.cloud.bigtable.grpc.async.BulkRead;
@@ -152,6 +153,8 @@ public class BigtableSession implements Closeable {
   private Watchdog watchdog;
   private final BigtableDataClient dataClient;
 
+  private final BigtableDataClientWrapper clientWrapper;
+
   // This BigtableDataClient has an additional throttling interceptor, which is not recommended for
   // synchronous operations.
   private final BigtableDataClient throttlingDataClient;
@@ -225,6 +228,9 @@ public class BigtableSession implements Closeable {
         new BigtableDataGrpcClient(dataChannel, sharedPools.getRetryExecutor(), options);
     dataClient.setCallOptionsFactory(callOptionsFactory);
 
+    this.clientWrapper =
+        new BigtableDataClientWrapper(dataClient, options);
+
     // Async operations can run amok, so they need to have some throttling. The throttling is
     // achieved through a ThrottlingClientInterceptor.  gRPC wraps ClientInterceptors in Channels,
     // and since a new Channel is needed, a new BigtableDataGrpcClient instance is needed as well.
@@ -299,6 +305,15 @@ public class BigtableSession implements Closeable {
     return dataClient;
   }
 
+  /**
+   * <p>Getter for the field <code>clientWrapper</code>.</p>
+   *
+   * @return a {@link BigtableDataClientWrapper} object.
+   */
+  public BigtableDataClientWrapper getClientWrapper() {
+    return clientWrapper;
+  }
+
   /**
    * <p>createAsyncExecutor.</p>
    *
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/AbstractBigtableRegionLocator.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/AbstractBigtableRegionLocator.java
index fde262dca..9b60c605d 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/AbstractBigtableRegionLocator.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/AbstractBigtableRegionLocator.java
@@ -21,6 +21,7 @@ import java.util.List;
 
 import javax.annotation.Nullable;
 
+import com.google.common.util.concurrent.MoreExecutors;
 import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
@@ -91,7 +92,7 @@ public abstract class AbstractBigtableRegionLocator {
             public List<HRegionLocation> apply(@Nullable List<SampleRowKeysResponse> input) {
               return adapter.adaptResponse(input);
             }
-          });
+          }, MoreExecutors.directExecutor());
       Futures.addCallback(this.regionsFuture, new FutureCallback<List<HRegionLocation>>() {
         @Override public void onSuccess(@Nullable List<HRegionLocation> result) {
         }
@@ -100,7 +101,7 @@ public abstract class AbstractBigtableRegionLocator {
             regionsFuture = null;
           }
         }
-      });
+      }, MoreExecutors.directExecutor());
       regionsFetchTimeMillis = System.currentTimeMillis();
       return this.regionsFuture;
     } catch(Throwable throwable) {
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/AbstractBigtableTable.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/AbstractBigtableTable.java
index 26e061893..41171e54a 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/AbstractBigtableTable.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/AbstractBigtableTable.java
@@ -18,6 +18,8 @@ package com.google.cloud.bigtable.hbase;
 import com.google.cloud.bigtable.data.v2.internal.RequestContext;
 import com.google.cloud.bigtable.data.v2.models.ConditionalRowMutation;
 import com.google.cloud.bigtable.data.v2.models.InstanceName;
+import com.google.cloud.bigtable.data.v2.models.RowMutation;
+import com.google.cloud.bigtable.grpc.BigtableDataClientWrapper;
 import io.opencensus.common.Scope;
 import io.opencensus.trace.Status;
 import java.io.IOException;
@@ -116,6 +118,7 @@ public abstract class AbstractBigtableTable implements Table {
   protected final HBaseRequestAdapter hbaseAdapter;
 
   protected final BigtableDataClient client;
+  protected final BigtableDataClientWrapper clientWrapper;
   private BatchExecutor batchExecutor;
   protected final AbstractBigtableConnection bigtableConnection;
   private TableMetrics metrics = new TableMetrics();
@@ -134,6 +137,7 @@ public abstract class AbstractBigtableTable implements Table {
     BigtableSession session = bigtableConnection.getSession();
     this.options = session.getOptions();
     this.client = session.getDataClient();
+    this.clientWrapper = session.getClientWrapper();
     this.hbaseAdapter = hbaseAdapter;
     this.tableName = hbaseAdapter.getTableName();
     this.requestContext = RequestContext.create(
@@ -352,7 +356,7 @@ public abstract class AbstractBigtableTable implements Table {
   @Override
   public void put(Put put) throws IOException {
     LOG.trace("put(Put)");
-    MutateRowRequest request = hbaseAdapter.adapt(put).toProto(requestContext);
+    RowMutation request = hbaseAdapter.adapt(put);
     mutateRow(put, request, "put");
   }
 
@@ -399,7 +403,7 @@ public abstract class AbstractBigtableTable implements Table {
   @Override
   public void delete(Delete delete) throws IOException {
     LOG.trace("delete(Delete)");
-    MutateRowRequest request = hbaseAdapter.adapt(delete).toProto(requestContext);
+    RowMutation request = hbaseAdapter.adapt(delete);
     mutateRow(delete, request, "delete");
   }
 
@@ -467,11 +471,11 @@ public abstract class AbstractBigtableTable implements Table {
     }
   }
 
-  private void mutateRow(Mutation mutation, MutateRowRequest mutateRowRequest, String type)
+  private void mutateRow(Mutation mutation, RowMutation mutateRowRequest, String type)
       throws IOException {
     Span span = TRACER.spanBuilder("BigtableTable." + type).startSpan();
     try (Scope scope = TRACER.withSpan(span)) {
-      client.mutateRow(mutateRowRequest);
+      clientWrapper.mutateRow(mutateRowRequest);
     } catch (Throwable t) {
       span.setStatus(Status.UNKNOWN);
       throw logAndCreateIOException(type, mutation.getRow(), t);
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/admin/ColumnDescriptorAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/admin/ColumnDescriptorAdapter.java
index bfc69fc6d..b857d943e 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/admin/ColumnDescriptorAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/admin/ColumnDescriptorAdapter.java
@@ -15,23 +15,22 @@
  */
 package com.google.cloud.bigtable.hbase.adapters.admin;
 
+import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES;
+
 import com.google.bigtable.admin.v2.ColumnFamily;
 import com.google.bigtable.admin.v2.GcRule;
-import com.google.bigtable.admin.v2.GcRule.Intersection;
 import com.google.bigtable.admin.v2.GcRule.RuleCase;
-import com.google.bigtable.admin.v2.GcRule.Union;
-import com.google.common.annotations.VisibleForTesting;
+import com.google.cloud.bigtable.admin.v2.models.GCRules.GCRule;
 import com.google.common.base.Joiner;
 import com.google.common.base.Preconditions;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
-import com.google.protobuf.Duration;
+import org.threeten.bp.Duration;
 
 import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HConstants;
 
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
@@ -164,12 +163,12 @@ public class ColumnDescriptorAdapter {
   }
 
   /**
-   * Construct an Bigtable {@link com.google.bigtable.admin.v2.GcRule} from the given column descriptor.
+   * Construct an Bigtable {@link GCRule} from the given column descriptor.
    *
    * @param columnDescriptor a {@link org.apache.hadoop.hbase.HColumnDescriptor} object.
-   * @return a {@link com.google.bigtable.admin.v2.GcRule} object.
+   * @return a {@link GCRule} object.
    */
-  public static GcRule buildGarbageCollectionRule(HColumnDescriptor columnDescriptor) {
+  public static GCRule buildGarbageCollectionRule(HColumnDescriptor columnDescriptor) {
     int maxVersions = columnDescriptor.getMaxVersions();
     int minVersions = columnDescriptor.getMinVersions();
     int ttlSeconds = columnDescriptor.getTimeToLive();
@@ -181,12 +180,12 @@ public class ColumnDescriptorAdapter {
       if (maxVersions == Integer.MAX_VALUE) {
         return null;
       } else {
-        return maxVersions(maxVersions);
+        return GCRULES.maxVersions(maxVersions);
       }
     }
 
     // minVersions only comes into play with a TTL:
-    GcRule ageRule = maxAge(ttlSeconds);
+    GCRule ageRule = GCRULES.maxAge(Duration.ofSeconds(ttlSeconds));
     if (minVersions != HColumnDescriptor.DEFAULT_MIN_VERSIONS) {
       // The logic here is: only delete a cell if:
       //  1) the age is older than :ttlSeconds AND
@@ -196,43 +195,15 @@ public class ColumnDescriptorAdapter {
       // Intersection (AND)
       //    - maxAge = :HBase_ttlSeconds
       //    - maxVersions = :HBase_minVersion
-      ageRule = intersection(ageRule, maxVersions(minVersions));
+      ageRule = GCRULES.intersection().rule(ageRule).rule(GCRULES.maxVersions(minVersions));
     }
     if (maxVersions == Integer.MAX_VALUE) {
       return ageRule;
     } else {
-      return union(ageRule, maxVersions(maxVersions));
+      return GCRULES.union().rule(ageRule).rule(GCRULES.maxVersions(maxVersions));
     }
   }
 
-  @VisibleForTesting
-  static GcRule intersection(GcRule... rules) {
-    return GcRule.newBuilder()
-        .setIntersection(Intersection.newBuilder().addAllRules(Arrays.asList(rules)).build())
-        .build();
-  }
-
-  @VisibleForTesting
-  static GcRule union(GcRule... rules) {
-    return GcRule.newBuilder()
-        .setUnion(Union.newBuilder().addAllRules(Arrays.asList(rules)).build())
-        .build();
-  }
-
-  private static Duration duration(int ttlSeconds) {
-    return Duration.newBuilder().setSeconds(ttlSeconds).build();
-  }
-
-  @VisibleForTesting
-  static GcRule maxAge(int ttlSeconds) {
-    return GcRule.newBuilder().setMaxAge(duration(ttlSeconds)).build();
-  }
-
-  @VisibleForTesting
-  static GcRule maxVersions(int maxVersions) {
-    return GcRule.newBuilder().setMaxNumVersions(maxVersions).build();
-  }
-
   /**
    * <p>
    * Parse a Bigtable {@link GcRule} that is in line with
@@ -338,9 +309,9 @@ public class ColumnDescriptorAdapter {
     throwIfRequestingUnsupportedFeatures(columnDescriptor);
 
     ColumnFamily.Builder resultBuilder = ColumnFamily.newBuilder();
-    GcRule gcRule = buildGarbageCollectionRule(columnDescriptor);
+    GCRule gcRule = buildGarbageCollectionRule(columnDescriptor);
     if (gcRule != null) {
-      resultBuilder.setGcRule(gcRule);
+      resultBuilder.setGcRule(gcRule.toProto());
     }
     return resultBuilder.build();
   }
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/admin/TableAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/admin/TableAdapter.java
index 26a7d4659..199c0ee1f 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/admin/TableAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/adapters/admin/TableAdapter.java
@@ -15,8 +15,11 @@
  */
 package com.google.cloud.bigtable.hbase.adapters.admin;
 
+import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.buildGarbageCollectionRule;
+
+import com.google.api.core.InternalApi;
 import com.google.bigtable.admin.v2.ColumnFamily;
-import com.google.bigtable.admin.v2.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
 import com.google.bigtable.admin.v2.Table;
 import com.google.cloud.bigtable.grpc.BigtableInstanceName;
 
@@ -26,8 +29,6 @@ import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.TableName;
 
-import java.util.HashMap;
-import java.util.Map;
 import java.util.Map.Entry;
 
 /**
@@ -36,42 +37,40 @@ import java.util.Map.Entry;
  * @author sduskis
  * @version $Id: $Id
  */
+@InternalApi
 public class TableAdapter {
   private static final ColumnDescriptorAdapter columnDescriptorAdapter =
       ColumnDescriptorAdapter.INSTANCE;
   protected final BigtableInstanceName bigtableInstanceName;
 
-
-
   /**
    * <p>adapt.</p>
    *
-   * @param desc a {@link org.apache.hadoop.hbase.HTableDescriptor} object.
-   * @return a {@link com.google.bigtable.admin.v2.Table} object.
+   * This method adapts ColumnFamily to CreateTableRequest.
+   *
+   * @param desc a {@link HTableDescriptor} object.
+   * @param  request a {@link CreateTableRequest}
    */
-  protected static Table adapt(HTableDescriptor desc) {
-    Map<String, ColumnFamily> columnFamilies = new HashMap<>();
-    for (HColumnDescriptor column : desc.getColumnFamilies()) {
-      String columnName = column.getNameAsString();
-      ColumnFamily columnFamily = columnDescriptorAdapter.adapt(column);
-      columnFamilies.put(columnName, columnFamily);
+  protected static void adapt(HTableDescriptor desc, CreateTableRequest request) {
+    if(request != null) {
+      for (HColumnDescriptor column : desc.getColumnFamilies()) {
+        String columnName = column.getNameAsString();
+        request.addFamily(columnName, buildGarbageCollectionRule(column));
+      }
     }
-    return Table.newBuilder().putAllColumnFamilies(columnFamilies).build();
   }
 
-  public static CreateTableRequest.Builder adapt(HTableDescriptor desc, byte[][] splitKeys) {
-    CreateTableRequest.Builder builder = CreateTableRequest.newBuilder();
-    builder.setTableId(desc.getTableName().getQualifierAsString());
-    builder.setTable(adapt(desc));
-    addSplitKeys(builder, splitKeys);
-    return builder;
+  public static CreateTableRequest adapt(HTableDescriptor desc, byte[][] splitKeys) {
+    CreateTableRequest request = CreateTableRequest.of(desc.getTableName().getNameAsString());
+    adapt(desc, request);
+    addSplitKeys(splitKeys, request);
+    return request;
   }
 
-  public static void addSplitKeys(CreateTableRequest.Builder builder, byte[][] splitKeys) {
+  public static void addSplitKeys(byte[][] splitKeys, CreateTableRequest request) {
     if (splitKeys != null) {
       for (byte[] splitKey : splitKeys) {
-        builder.addInitialSplits(
-            CreateTableRequest.Split.newBuilder().setKey(ByteString.copyFrom(splitKey)).build());
+        request.addSplit(ByteString.copyFrom(splitKey));
       }
     }
   }
@@ -89,8 +88,8 @@ public class TableAdapter {
   /**
    * <p>adapt.</p>
    *
-   * @param table a {@link com.google.bigtable.admin.v2.Table} object.
-   * @return a {@link org.apache.hadoop.hbase.HTableDescriptor} object.
+   * @param table a {@link Table} object.
+   * @return a {@link HTableDescriptor} object.
    */
   public HTableDescriptor adapt(Table table) {
     String tableId = bigtableInstanceName.toTableId(table.getName());
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/util/ModifyTableBuilder.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/util/ModifyTableBuilder.java
index 7ac51b618..22e5bec48 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/util/ModifyTableBuilder.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/com/google/cloud/bigtable/hbase/util/ModifyTableBuilder.java
@@ -15,28 +15,31 @@
  */
 package com.google.cloud.bigtable.hbase.util;
 
-import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest;
-import com.google.cloud.bigtable.grpc.BigtableTableName;
-import com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter;
+import com.google.api.core.InternalApi;
+import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
+import com.google.common.base.Preconditions;
 import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.util.Bytes;
 
-import java.util.ArrayList;
 import java.util.HashSet;
-import java.util.List;
 import java.util.Set;
 
+import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.buildGarbageCollectionRule;
 /**
  * Utilitiy to create {@link ModifyColumnFamiliesRequest} from HBase {@link HColumnDescriptor}s.
  */
+@InternalApi
 public class ModifyTableBuilder {
 
-  private static final ColumnDescriptorAdapter ADAPTER = new ColumnDescriptorAdapter();
 
-  public static ModifyTableBuilder create() {
-    return new ModifyTableBuilder();
+  private ModifyTableBuilder(String tableId){
+    this.request = ModifyColumnFamiliesRequest.of(tableId);
+  }
+
+  public static ModifyTableBuilder newBuilder(TableName tableName){
+    return new ModifyTableBuilder(tableName.getNameAsString());
   }
 
   private static Set<String> getColumnNames(HTableDescriptor tableDescriptor) {
@@ -48,22 +51,26 @@ public class ModifyTableBuilder {
   }
 
   /**
-   * This method will build list of of protobuf {@link ModifyColumnFamiliesRequest.Modification} objects based on a diff of the
+   * This method will build {@link ModifyColumnFamiliesRequest} objects based on a diff of the
    * new and existing set of column descriptors.  This is for use in
    * {@link org.apache.hadoop.hbase.client.Admin#modifyTable(TableName, HTableDescriptor)}.
    */
   public static ModifyTableBuilder buildModifications(
-      HTableDescriptor newTableDescriptor,
-      HTableDescriptor currentTableDescriptors) {
-    ModifyTableBuilder builder = new ModifyTableBuilder();
-    Set<String> currentColumnNames = getColumnNames(currentTableDescriptors);
-    Set<String> newColumnNames = getColumnNames(newTableDescriptor);
-
-    for (HColumnDescriptor hColumnDescriptor : newTableDescriptor.getFamilies()) {
-      if (currentColumnNames.contains(hColumnDescriptor.getNameAsString())) {
-        builder.modify(hColumnDescriptor);
+          HTableDescriptor newTableDesc,
+          HTableDescriptor currentTableDesc) {
+    Preconditions.checkNotNull(newTableDesc);
+    Preconditions.checkNotNull(currentTableDesc);
+
+    ModifyTableBuilder requestBuilder = ModifyTableBuilder.newBuilder(currentTableDesc.getTableName());
+    Set<String> currentColumnNames = getColumnNames(currentTableDesc);
+    Set<String> newColumnNames = getColumnNames(newTableDesc);
+
+    for (HColumnDescriptor hColumnDescriptor : newTableDesc.getFamilies()) {
+      String columnName = hColumnDescriptor.getNameAsString();
+      if (currentColumnNames.contains(columnName)) {
+        requestBuilder.modify(hColumnDescriptor);
       } else {
-        builder.add(hColumnDescriptor);
+        requestBuilder.add(hColumnDescriptor);
       }
     }
 
@@ -71,47 +78,31 @@ public class ModifyTableBuilder {
     columnsToRemove.removeAll(newColumnNames);
 
     for (String column : columnsToRemove) {
-      builder.delete(column);
+      requestBuilder.delete(column);
     }
-    return builder;
+    return requestBuilder;
   }
 
-  private final List<ModifyColumnFamiliesRequest.Modification> modifications = new ArrayList<>();
+  private final ModifyColumnFamiliesRequest request;
 
-  public ModifyTableBuilder add(HColumnDescriptor descriptor) {
-    String columnName = descriptor.getNameAsString();
-    modifications.add(ModifyColumnFamiliesRequest.Modification
-        .newBuilder()
-        .setId(columnName)
-        .setCreate(ADAPTER.adapt(descriptor))
-        .build());
+  public ModifyTableBuilder add(HColumnDescriptor addColumnFamily) {
+    this.request.addFamily(addColumnFamily.getNameAsString(),
+            buildGarbageCollectionRule(addColumnFamily));
     return this;
   }
 
-  public ModifyTableBuilder modify(HColumnDescriptor descriptor) {
-    String columnName = descriptor.getNameAsString();
-    modifications.add(ModifyColumnFamiliesRequest.Modification
-        .newBuilder()
-        .setId(columnName)
-        .setUpdate(ADAPTER.adapt(descriptor))
-        .build());
+  public ModifyTableBuilder modify(HColumnDescriptor modifyColumnFamily) {
+    this.request.updateFamily(modifyColumnFamily.getNameAsString(),
+            buildGarbageCollectionRule(modifyColumnFamily));
     return this;
   }
 
-  public ModifyTableBuilder delete(String name) {
-    modifications.add(ModifyColumnFamiliesRequest.Modification
-        .newBuilder()
-        .setId(name)
-        .setDrop(true)
-        .build());
+  public ModifyTableBuilder delete(String familyId) {
+    this.request.dropFamily(familyId);
     return this;
   }
 
-  public ModifyColumnFamiliesRequest toProto(String name) {
-    return ModifyColumnFamiliesRequest
-        .newBuilder()
-        .setName(name)
-        .addAllModifications(modifications)
-        .build();
+  public ModifyColumnFamiliesRequest build(){
+    return request;
   }
 }
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/main/java/org/apache/hadoop/hbase/client/AbstractBigtableAdmin.java b/bigtable-client-core-parent/bigtable-hbase/src/main/java/org/apache/hadoop/hbase/client/AbstractBigtableAdmin.java
index 140436ba8..587d4d70a 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/main/java/org/apache/hadoop/hbase/client/AbstractBigtableAdmin.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/main/java/org/apache/hadoop/hbase/client/AbstractBigtableAdmin.java
@@ -15,8 +15,9 @@
  */
 package org.apache.hadoop.hbase.client;
 
+import static com.google.cloud.bigtable.hbase.util.ModifyTableBuilder.buildModifications;
+
 import com.google.bigtable.admin.v2.CreateTableFromSnapshotRequest;
-import com.google.bigtable.admin.v2.CreateTableRequest;
 import com.google.bigtable.admin.v2.DeleteSnapshotRequest;
 import com.google.bigtable.admin.v2.DeleteTableRequest;
 import com.google.bigtable.admin.v2.DeleteTableRequest.Builder;
@@ -26,6 +27,8 @@ import com.google.bigtable.admin.v2.ListTablesRequest;
 import com.google.bigtable.admin.v2.ListTablesResponse;
 import com.google.bigtable.admin.v2.SnapshotTableRequest;
 import com.google.bigtable.admin.v2.Table;
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
 import com.google.cloud.bigtable.config.BigtableOptions;
 import com.google.cloud.bigtable.config.Logger;
 import com.google.cloud.bigtable.grpc.BigtableClusterName;
@@ -38,6 +41,7 @@ import com.google.common.base.MoreObjects;
 import com.google.common.util.concurrent.FutureCallback;
 import com.google.common.util.concurrent.Futures;
 import com.google.common.util.concurrent.ListenableFuture;
+import com.google.common.util.concurrent.MoreExecutors;
 import com.google.common.util.concurrent.SettableFuture;
 import com.google.longrunning.Operation;
 import com.google.protobuf.ByteString;
@@ -100,7 +104,6 @@ public abstract class AbstractBigtableAdmin implements Admin {
   private final BigtableOptions options;
   protected final CommonConnection connection;
   protected final BigtableTableAdminClient bigtableTableAdminClient;
-
   protected final BigtableInstanceName bigtableInstanceName;
   private BigtableClusterName bigtableSnapshotClusterName;
   protected final TableAdapter tableAdapter;
@@ -109,7 +112,7 @@ public abstract class AbstractBigtableAdmin implements Admin {
    * <p>
    * Constructor for AbstractBigtableAdmin.
    * </p>
-   * @param connection a {@link org.apache.hadoop.hbase.client.AbstractBigtableConnection} object.
+   * @param connection a {@link CommonConnection} object.
    * @throws IOException
    */
   public AbstractBigtableAdmin(CommonConnection connection) throws IOException {
@@ -357,10 +360,15 @@ public abstract class AbstractBigtableAdmin implements Admin {
     createTable(desc.getTableName(), TableAdapter.adapt(desc, splitKeys));
   }
 
-  protected void createTable(TableName tableName, CreateTableRequest.Builder builder) throws IOException {
-    builder.setParent(bigtableInstanceName.toString());
+  /**
+   * @param request a {@link CreateTableRequest} object to send.
+   * @throws java.io.IOException if any.
+   */
+  protected void createTable(TableName tableName, CreateTableRequest request)
+          throws IOException {
     try {
-      bigtableTableAdminClient.createTable(builder.build());
+      bigtableTableAdminClient.createTable(
+              request.toProto(bigtableInstanceName.toAdminInstanceName()));
     } catch (Throwable throwable) {
       throw convertToTableExistsException(tableName, throwable);
     }
@@ -370,14 +378,19 @@ public abstract class AbstractBigtableAdmin implements Admin {
   @Override
   public void createTableAsync(final HTableDescriptor desc, byte[][] splitKeys) throws IOException {
     LOG.warn("Creating the table synchronously");
-    CreateTableRequest.Builder builder = TableAdapter.adapt(desc, splitKeys);
-    createTableAsync(builder, desc.getTableName());
+    createTableAsync(desc.getTableName(), TableAdapter.adapt(desc, splitKeys));
   }
 
-  protected ListenableFuture<Table> createTableAsync(CreateTableRequest.Builder builder,
-      final TableName tableName) throws IOException {
-    builder.setParent(bigtableInstanceName.toString());
-    ListenableFuture<Table> future = bigtableTableAdminClient.createTableAsync(builder.build());
+  /**
+   * @param tableName a {@link TableName} object for exception identification.
+   * @param request a {@link CreateTableRequest} object to send.
+   * @throws java.io.IOException if any.
+   */
+  protected ListenableFuture<Table> createTableAsync(final TableName tableName,
+            CreateTableRequest request) throws IOException {
+    ListenableFuture<Table> future =
+            bigtableTableAdminClient.createTableAsync(
+                    request.toProto(bigtableInstanceName.toAdminInstanceName()));
     final SettableFuture<Table> settableFuture = SettableFuture.create();
     Futures.addCallback(future, new FutureCallback<Table>() {
       @Override public void onSuccess(@Nullable Table result) {
@@ -387,7 +400,7 @@ public abstract class AbstractBigtableAdmin implements Admin {
       @Override public void onFailure(Throwable t) {
         settableFuture.setException(convertToTableExistsException(tableName, t));
       }
-    });
+    }, MoreExecutors.directExecutor());
     return settableFuture;
   }
 
@@ -578,14 +591,14 @@ public abstract class AbstractBigtableAdmin implements Admin {
   @Override
   public void addColumn(TableName tableName, HColumnDescriptor column) throws IOException {
     modifyColumns(tableName, column.getNameAsString(), "add",
-        ModifyTableBuilder.create().add(column));
+        ModifyTableBuilder.newBuilder(tableName).add(column));
   }
 
   /** {@inheritDoc} */
   @Override
   public void modifyColumn(TableName tableName, HColumnDescriptor column) throws IOException {
     modifyColumns(tableName, column.getNameAsString(), "modify",
-        ModifyTableBuilder.create().modify(column));
+        ModifyTableBuilder.newBuilder(tableName).modify(column));
   }
 
   /** {@inheritDoc} */
@@ -593,7 +606,7 @@ public abstract class AbstractBigtableAdmin implements Admin {
   public void deleteColumn(TableName tableName, byte[] columnName) throws IOException {
     String name = Bytes.toString(columnName);
     modifyColumns(tableName, name, "delete",
-        ModifyTableBuilder.create().delete(name));
+        ModifyTableBuilder.newBuilder(tableName).delete(name));
   }
 
   /** {@inheritDoc} */
@@ -601,9 +614,10 @@ public abstract class AbstractBigtableAdmin implements Admin {
   public void modifyTable(TableName tableName, HTableDescriptor newDecriptor) throws IOException {
     if (isTableAvailable(tableName)) {
       try {
-        ModifyTableBuilder builder =
-            ModifyTableBuilder.buildModifications(newDecriptor, getTableDescriptor(tableName));
-        bigtableTableAdminClient.modifyColumnFamily(builder.toProto(toBigtableName(tableName)));
+        ModifyColumnFamiliesRequest request =
+            buildModifications(newDecriptor, getTableDescriptor(tableName)).build();
+        bigtableTableAdminClient.modifyColumnFamily(
+                request.toProto(bigtableInstanceName.toAdminInstanceName()));
       } catch (Throwable throwable) {
         throw new IOException(
             String.format("Failed to modify table '%s'", tableName.getNameAsString()), throwable);
@@ -624,9 +638,10 @@ public abstract class AbstractBigtableAdmin implements Admin {
    */
   protected Void modifyColumns(TableName tableName, String columnName,
       String modificationType, ModifyTableBuilder builder) throws IOException {
-
+    ModifyColumnFamiliesRequest request = builder.build();
     try {
-      bigtableTableAdminClient.modifyColumnFamily(builder.toProto(toBigtableName(tableName)));
+      bigtableTableAdminClient.modifyColumnFamily(
+              request.toProto(bigtableInstanceName.toAdminInstanceName()));
       return null;
     } catch (Throwable throwable) {
       throw new IOException(
@@ -1386,5 +1401,4 @@ public abstract class AbstractBigtableAdmin implements Admin {
   public void rollWALWriter(ServerName serverName) throws IOException, FailedLogCloseException {
     throw new UnsupportedOperationException("rollWALWriter");  // TODO
   }
-
 }
diff --git a/bigtable-dataflow-parent/bigtable-hbase-dataflow/src/main/java/com/google/cloud/bigtable/dataflow/CloudBigtableIO.java b/bigtable-dataflow-parent/bigtable-hbase-dataflow/src/main/java/com/google/cloud/bigtable/dataflow/CloudBigtableIO.java
index c858b3728..6031d9166 100644
--- a/bigtable-dataflow-parent/bigtable-hbase-dataflow/src/main/java/com/google/cloud/bigtable/dataflow/CloudBigtableIO.java
+++ b/bigtable-dataflow-parent/bigtable-hbase-dataflow/src/main/java/com/google/cloud/bigtable/dataflow/CloudBigtableIO.java
@@ -15,7 +15,6 @@
  */
 package com.google.cloud.bigtable.dataflow;
 
-import static com.google.bigtable.repackaged.com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Strings.isNullOrEmpty;
 
 import java.io.IOException;
@@ -29,6 +28,7 @@ import java.util.NoSuchElementException;
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicLong;
 
+import com.google.common.base.Preconditions;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.TableName;
@@ -48,7 +48,6 @@ import org.apache.hadoop.hbase.util.Bytes;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.google.api.client.util.Preconditions;
 import com.google.bigtable.repackaged.com.google.bigtable.v2.SampleRowKeysRequest;
 import com.google.bigtable.repackaged.com.google.bigtable.v2.SampleRowKeysResponse;
 import com.google.bigtable.repackaged.com.google.cloud.bigtable.config.BulkOptions;
@@ -1327,7 +1326,7 @@ public class CloudBigtableIO {
   }
 
   private static void checkNotNullOrEmpty(String value, String type) {
-    checkArgument(
+    Preconditions.checkArgument(
         !isNullOrEmpty(value), "A " + type + " must be set to configure Bigtable properly.");
   }
 
diff --git a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/BigtableAdmin.java b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/BigtableAdmin.java
index 58c065d90..f3627d47d 100644
--- a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/BigtableAdmin.java
+++ b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/BigtableAdmin.java
@@ -15,6 +15,10 @@
  */
 package com.google.cloud.bigtable.hbase2_x;
 
+import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.buildGarbageCollectionRule;
+import static com.google.cloud.bigtable.hbase.util.ModifyTableBuilder.buildModifications;
+
+import com.google.cloud.bigtable.hbase.util.ModifyTableBuilder;
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -65,14 +69,11 @@ import com.google.bigtable.admin.v2.DeleteTableRequest;
 import com.google.bigtable.admin.v2.DropRowRangeRequest;
 import com.google.bigtable.admin.v2.ListSnapshotsRequest;
 import com.google.bigtable.admin.v2.ListSnapshotsResponse;
-import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest;
-import com.google.bigtable.admin.v2.ModifyColumnFamiliesRequest.Modification;
 import com.google.bigtable.admin.v2.Snapshot;
-import com.google.cloud.bigtable.hbase.util.ModifyTableBuilder;
+import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
 import com.google.cloud.bigtable.hbase2_x.adapters.admin.TableAdapter2x;
 import com.google.common.util.concurrent.Futures;
 
-
 /**
  * HBase 2.x specific implementation of {@link AbstractBigtableAdmin}.
  * @author spollapally
@@ -100,7 +101,6 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
     createTable(desc, createSplitKeys(startKey, endKey, numRegions));
   }
 
-
   /** {@inheritDoc} */
   @Override
   public void createTable(TableDescriptor desc, byte[][] splitKeys) throws IOException {
@@ -133,7 +133,7 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
     return response;
 
   }
-  
+
   @Override
   public List<SnapshotDescription> listSnapshots()
       throws IOException {
@@ -146,16 +146,15 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
     List<SnapshotDescription> response = new ArrayList<>();
     for (Snapshot snapshot : snapshotList.getSnapshotsList()) {
       response.add(new SnapshotDescription(
-          snapshot.getName(), 
+          snapshot.getName(),
           TableName.valueOf(snapshot.getSourceTable().getName())));
     }
     return response;
   }
 
-
   /**
    * {@inheritDoc}
-   * 
+   *
    * Calling {@link #addColumn(TableName, ColumnFamilyDescriptor)} was causing stackoverflow.
    * Copying the same code here. //TODO - need to find a better way
    */
@@ -163,20 +162,20 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
   public void addColumnFamily(TableName tableName, ColumnFamilyDescriptor columnFamilyDesc)
       throws IOException {
     modifyColumns(tableName, columnFamilyDesc.getNameAsString(), "add",
-        ModifyTableBuilder.create().add(TableAdapter2x.toHColumnDescriptor(columnFamilyDesc)));
+            ModifyTableBuilder.newBuilder(tableName).add(TableAdapter2x.toHColumnDescriptor(columnFamilyDesc)));
   }
 
   /**
    * {@inheritDoc}
-   * 
+   *
    * Calling {@link #addColumn(TableName, ColumnFamilyDescriptor)} was causing stackoverflow.
-   * Copying the same code here. //TODO - need to find a better way 
+   * Copying the same code here. //TODO - need to find a better way
    */
   @Override
   public void modifyColumnFamily(TableName tableName, ColumnFamilyDescriptor columnFamilyDesc)
       throws IOException {
     modifyColumns(tableName, columnFamilyDesc.getNameAsString(), "modify",
-        ModifyTableBuilder.create().modify(TableAdapter2x.toHColumnDescriptor(columnFamilyDesc)));
+        ModifyTableBuilder.newBuilder(tableName).modify(TableAdapter2x.toHColumnDescriptor(columnFamilyDesc)));
   }
 
   /** {@inheritDoc} */
@@ -244,18 +243,6 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
     return asyncAdmin.deleteColumnFamily(tableName, columnName);
   }
 
-
-  protected CompletableFuture<Void> modifyColumnsAsync(TableName tableName, Modification... modifications) {
-    ModifyColumnFamiliesRequest modifyColumnRequest = ModifyColumnFamiliesRequest
-        .newBuilder()
-        .addAllModifications(Arrays.asList(modifications))
-        .setName(toBigtableName(tableName))
-        .build();
-    return FutureUtils.toCompletableFuture(
-        bigtableTableAdminClient.modifyColumnFamilyAsync(modifyColumnRequest))
-        .thenApply(r -> null);
-  }
-
   protected CompletableFuture<Void> deleteTableAsyncInternal(TableName tableName) {
     DeleteTableRequest deleteTableRequest = DeleteTableRequest.newBuilder()
         .setName(toBigtableName(tableName))
@@ -264,7 +251,7 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
         bigtableTableAdminClient.deleteTableAsync(deleteTableRequest))
         .thenApply(r -> null);
   }
-  
+
   @Override
   public Future<Void> deleteTableAsync(TableName tableName) throws IOException {
     return deleteTableAsyncInternal(tableName);
@@ -293,13 +280,13 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
   }
 
   @Override
-  public List<TableDescriptor> listTableDescriptors(Pattern pattern, boolean includeSysTables) 
+  public List<TableDescriptor> listTableDescriptors(Pattern pattern, boolean includeSysTables)
       throws IOException {
     return Arrays.asList(listTables(pattern,includeSysTables));
   }
 
   @Override
-  public List<TableDescriptor> listTableDescriptorsByNamespace(byte[] namespace) 
+  public List<TableDescriptor> listTableDescriptorsByNamespace(byte[] namespace)
       throws IOException {
     final String namespaceStr = Bytes.toString(namespace);
     return Arrays.asList(listTableDescriptorsByNamespace(namespaceStr));
@@ -324,7 +311,7 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
   }
 
   @Override
-  public Future<Void> modifyColumnFamilyAsync(TableName tableName, 
+  public Future<Void> modifyColumnFamilyAsync(TableName tableName,
       ColumnFamilyDescriptor columnFamily) throws IOException {
     return asyncAdmin.modifyColumnFamily(tableName, columnFamily);
   }
@@ -338,7 +325,7 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
   public void modifyTable(TableName tableName, TableDescriptor tableDescriptor) throws IOException {
     super.modifyTable(tableName, new HTableDescriptor(tableDescriptor));
   }
-  
+
   @Override
   public Future<Void> modifyTableAsync(TableDescriptor tableDescriptor)
       throws IOException {
@@ -358,7 +345,6 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
         });
   }
 
-
   /* (non-Javadoc)
    * @see org.apache.hadoop.hbase.client.Admin#truncateTableAsync(org.apache.hadoop.hbase.TableName, boolean)
    */
@@ -787,4 +773,4 @@ public class BigtableAdmin extends AbstractBigtableAdmin {
       ReplicationPeerConfig replicationPeerConfig) {
     throw new UnsupportedOperationException("updateReplicationPeerConfigAsync"); // TODO
   }
-}
\ No newline at end of file
+}
diff --git a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/BigtableAsyncAdmin.java b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/BigtableAsyncAdmin.java
index b65c95776..64e0b3040 100644
--- a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/BigtableAsyncAdmin.java
+++ b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/BigtableAsyncAdmin.java
@@ -15,8 +15,11 @@
  */
 package com.google.cloud.bigtable.hbase2_x;
 
+import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.buildGarbageCollectionRule;
+import static com.google.cloud.bigtable.hbase2_x.FutureUtils.failedFuture;
+import static com.google.cloud.bigtable.hbase.util.ModifyTableBuilder.buildModifications;
+
 import com.google.bigtable.admin.v2.CreateTableFromSnapshotRequest;
-import com.google.bigtable.admin.v2.CreateTableRequest;
 import com.google.bigtable.admin.v2.DeleteSnapshotRequest;
 import com.google.bigtable.admin.v2.DeleteTableRequest;
 import com.google.bigtable.admin.v2.DropRowRangeRequest;
@@ -26,6 +29,8 @@ import com.google.bigtable.admin.v2.ListTablesRequest;
 import com.google.bigtable.admin.v2.Snapshot;
 import com.google.bigtable.admin.v2.SnapshotTableRequest;
 import com.google.bigtable.admin.v2.Table;
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
 import com.google.cloud.bigtable.config.BigtableOptions;
 import com.google.cloud.bigtable.config.Logger;
 import com.google.cloud.bigtable.grpc.BigtableClusterName;
@@ -83,8 +88,6 @@ import java.util.function.Predicate;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
-import static com.google.cloud.bigtable.hbase2_x.FutureUtils.failedFuture;
-
 /**
  * Bigtable implementation of {@link AsyncAdmin}
  *
@@ -127,9 +130,9 @@ public class BigtableAsyncAdmin implements AsyncAdmin {
       return failedFuture(new IllegalArgumentException("TableName cannot be null"));
     }
 
-    CreateTableRequest.Builder builder = TableAdapter2x.adapt(desc, splitKeys);
-    builder.setParent(bigtableInstanceName.toString());
-    return bigtableTableAdminClient.createTableAsync(builder.build())
+    CreateTableRequest request = TableAdapter2x.adapt(desc, splitKeys);
+    return bigtableTableAdminClient.createTableAsync(
+            request.toProto(bigtableInstanceName.toAdminInstanceName()))
         .handle((resp, ex) -> {
           if (ex != null) {
             throw new CompletionException(
@@ -332,21 +335,21 @@ public class BigtableAsyncAdmin implements AsyncAdmin {
   public CompletableFuture<Void> addColumnFamily(TableName tableName,
       ColumnFamilyDescriptor columnFamilyDesc) {
     return modifyColumns(tableName,
-        ModifyTableBuilder.create().add(TableAdapter2x.toHColumnDescriptor(columnFamilyDesc)));
+        ModifyTableBuilder.newBuilder(tableName).add(TableAdapter2x.toHColumnDescriptor(columnFamilyDesc)));
   }
 
 
   @Override
   public CompletableFuture<Void> deleteColumnFamily(TableName tableName,
       byte[] columnName) {
-    return modifyColumns(tableName, ModifyTableBuilder.create().delete(Bytes.toString(columnName)));
+    return modifyColumns(tableName, ModifyTableBuilder.newBuilder(tableName).delete(Bytes.toString(columnName)));
   }
 
   @Override
   public CompletableFuture<Void> modifyColumnFamily(TableName tableName,
       ColumnFamilyDescriptor columnFamilyDesc) {
     return modifyColumns(tableName,
-        ModifyTableBuilder.create().modify(TableAdapter2x.toHColumnDescriptor(columnFamilyDesc)));
+        ModifyTableBuilder.newBuilder(tableName).modify(TableAdapter2x.toHColumnDescriptor(columnFamilyDesc)));
   }
 
   @Override
@@ -374,8 +377,9 @@ public class BigtableAsyncAdmin implements AsyncAdmin {
    */
   private CompletableFuture<Void> modifyColumns(TableName tableName,
       ModifyTableBuilder modifications) {
+    ModifyColumnFamiliesRequest request = modifications.build();
     return bigtableTableAdminClient
-        .modifyColumnFamilyAsync(modifications.toProto(toBigtableName(tableName)))
+        .modifyColumnFamilyAsync(request.toProto(bigtableInstanceName.toAdminInstanceName()))
         .thenApply(r -> null);
   }
 
@@ -588,8 +592,8 @@ public class BigtableAsyncAdmin implements AsyncAdmin {
 
   @Override
   public CompletableFuture<List<SnapshotDescription>> listTableSnapshots(Pattern tableNamePattern) {
-    return listSnapshots().thenApply(r -> 
-    		filter(r, d->tableNamePattern == null || 
+    return listSnapshots().thenApply(r ->
+    		filter(r, d->tableNamePattern == null ||
     		tableNamePattern.matcher(d.getTableNameAsString()).matches()));
   }
 
@@ -617,7 +621,6 @@ public class BigtableAsyncAdmin implements AsyncAdmin {
     });
   }
 
-
   private BigtableClusterName getSnapshotClusterName() throws IOException {
     if (bigtableSnapshotClusterName == null) {
       try {
@@ -693,7 +696,7 @@ public class BigtableAsyncAdmin implements AsyncAdmin {
   public CompletableFuture<Void> decommissionRegionServers(List<ServerName> arg0, boolean arg1) {
     throw new UnsupportedOperationException("decommissionRegionServers"); // TODO
   }
-  
+
   @Override
   public CompletableFuture<Void> deleteNamespace(String arg0) {
     throw new UnsupportedOperationException("deleteNamespace"); // TODO
diff --git a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/FutureUtils.java b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/FutureUtils.java
index 62621abc0..a082576d1 100644
--- a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/FutureUtils.java
+++ b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/FutureUtils.java
@@ -55,7 +55,7 @@ public class FutureUtils {
         completableFuture.complete(t);
       }
     };
-    Futures.addCallback(listenableFuture, callback);
+    Futures.addCallback(listenableFuture, callback, MoreExecutors.directExecutor());
 
     return completableFuture;
   }
diff --git a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/adapters/admin/TableAdapter2x.java b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/adapters/admin/TableAdapter2x.java
index a676a0a14..6110cdb95 100644
--- a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/adapters/admin/TableAdapter2x.java
+++ b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/main/java/com/google/cloud/bigtable/hbase2_x/adapters/admin/TableAdapter2x.java
@@ -15,13 +15,9 @@
  */
 package com.google.cloud.bigtable.hbase2_x.adapters.admin;
 
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import com.google.api.core.InternalApi;
 
-import com.google.bigtable.admin.v2.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
 import com.google.cloud.bigtable.grpc.BigtableInstanceName;
 import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HTableDescriptor;
@@ -29,37 +25,28 @@ import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
 import org.apache.hadoop.hbase.client.TableDescriptor;
 import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
-import org.apache.hadoop.hbase.util.Bytes;
-import com.google.bigtable.admin.v2.ColumnFamily;
 import com.google.bigtable.admin.v2.Table;
 import com.google.cloud.bigtable.config.BigtableOptions;
 import com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter;
 import com.google.cloud.bigtable.hbase.adapters.admin.TableAdapter;
 
 /**
- * Need this extended class as {@link TableAdapter#adapt(org.apache.hadoop.hbase.HTableDescriptor)}
- * is not binary compatible with {@link TableAdapter2x#adapt(TableDescriptor)}
+ * Need this extended class as {@link TableAdapter#adapt(HTableDescriptor, CreateTableRequest)}
+ * is not binary compatible with {@link TableAdapter2x#adapt(TableDescriptor, byte[][])}
  * 
  * Similarly, {@link ColumnDescriptorAdapter#adapt(HColumnDescriptor)} is not binary compatible with
  * {@link ColumnFamilyDescriptor}.
  * 
  * @author spollapally
  */
+@InternalApi
 public class TableAdapter2x {
   protected static final ColumnDescriptorAdapter columnDescriptorAdapter = new ColumnDescriptorAdapter();
 
-  public static CreateTableRequest.Builder adapt(TableDescriptor desc, byte[][] splitKeys) {
+  public static CreateTableRequest adapt(TableDescriptor desc, byte[][] splitKeys) {
     return TableAdapter.adapt(new HTableDescriptor(desc), splitKeys);
   }
 
-  public static Table adapt(TableDescriptor desc) {
-    return adapt(new HTableDescriptor(desc), null).getTable();
-  }
-
-  public static ColumnFamily toColumnFamily(ColumnFamilyDescriptor column) {
-    return columnDescriptorAdapter.adapt(toHColumnDescriptor(column));
-  }
-
   public static HColumnDescriptor toHColumnDescriptor(ColumnFamilyDescriptor column) {
     TableDescriptor desc =
         TableDescriptorBuilder.newBuilder(TableName.valueOf("N_A")).setColumnFamily(column)
diff --git a/pom.xml b/pom.xml
index 2e52a6ac0..779a7fd65 100644
--- a/pom.xml
+++ b/pom.xml
@@ -59,9 +59,9 @@ limitations under the License.
         <hamcrest.version>1.3</hamcrest.version>
 
         <!-- google-cloud-java related dependency versions -->
-        <google-cloud.version>0.67.0-alpha</google-cloud.version>
+        <google-cloud.version>0.71.0-alpha</google-cloud.version>
         <opencensus.version>0.15.0</opencensus.version>
-        <guava.version>20.0</guava.version>
+        <guava.version>26.0-android</guava.version>
 
         <!-- hbase dependency versions -->
         <hbase.version.1>1.4.5</hbase.version.1>


Test patch:
diff --git a/bigtable-client-core-parent/bigtable-client-core/src/test/java/com/google/cloud/bigtable/grpc/TestBigtableInstanceName.java b/bigtable-client-core-parent/bigtable-client-core/src/test/java/com/google/cloud/bigtable/grpc/TestBigtableInstanceName.java
index 75a476db0..a20a9de08 100644
--- a/bigtable-client-core-parent/bigtable-client-core/src/test/java/com/google/cloud/bigtable/grpc/TestBigtableInstanceName.java
+++ b/bigtable-client-core-parent/bigtable-client-core/src/test/java/com/google/cloud/bigtable/grpc/TestBigtableInstanceName.java
@@ -15,6 +15,7 @@
  */
 package com.google.cloud.bigtable.grpc;
 
+import com.google.cloud.bigtable.data.v2.models.InstanceName;
 import org.junit.Assert;
 import org.junit.Rule;
 import org.junit.Test;
@@ -97,4 +98,15 @@ public class TestBigtableInstanceName {
     expectedException.expect(IllegalArgumentException.class);
     new BigtableInstanceName("project", "");
   }
+
+  @Test
+  public void testGcbInstanceName(){
+    Assert.assertTrue(bigtableInstanceName.toGcbInstanceName() instanceof InstanceName);
+  }
+
+  @Test
+  public void testAdminInstanceName(){
+    Assert.assertTrue(bigtableInstanceName.toAdminInstanceName() instanceof
+            com.google.bigtable.admin.v2.InstanceName);
+  }
 }
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/TestBigtableTable.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/TestBigtableTable.java
index 7bb058d42..97c7eeabe 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/TestBigtableTable.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/TestBigtableTable.java
@@ -23,19 +23,23 @@ import static org.mockito.Matchers.isA;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
-import com.google.bigtable.v2.MutateRowRequest;
 import com.google.bigtable.v2.ReadRowsRequest;
 import com.google.bigtable.v2.RowFilter;
 import com.google.bigtable.v2.RowFilter.Chain;
 import com.google.cloud.bigtable.config.BigtableOptions;
 import com.google.cloud.bigtable.config.RetryOptions;
+import com.google.cloud.bigtable.data.v2.internal.RequestContext;
+import com.google.cloud.bigtable.data.v2.models.InstanceName;
+import com.google.cloud.bigtable.data.v2.models.RowMutation;
 import com.google.cloud.bigtable.grpc.BigtableDataClient;
+import com.google.cloud.bigtable.grpc.BigtableDataClientWrapper;
 import com.google.cloud.bigtable.grpc.BigtableSession;
 import com.google.cloud.bigtable.grpc.scanner.FlatRow;
 import com.google.cloud.bigtable.grpc.scanner.ResultScanner;
 import com.google.cloud.bigtable.hbase.adapters.HBaseRequestAdapter;
 import com.google.protobuf.ByteString;
 
+import java.util.concurrent.ExecutionException;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.TableName;
@@ -82,6 +86,9 @@ public class TestBigtableTable {
   @Mock
   private BigtableDataClient mockClient;
 
+  @Mock
+  private BigtableDataClientWrapper mockBigtableDataClient;
+
   @Mock
   private ResultScanner<FlatRow> mockResultScanner;
 
@@ -110,21 +117,24 @@ public class TestBigtableTable {
     when(mockConnection.getSession()).thenReturn(mockSession);
     when(mockSession.getOptions()).thenReturn(options);
     when(mockSession.getDataClient()).thenReturn(mockClient);
+    when(mockSession.getClientWrapper()).thenReturn(mockBigtableDataClient);
     when(mockClient.readFlatRows(isA(ReadRowsRequest.class))).thenReturn(mockResultScanner);
     table = new AbstractBigtableTable(mockConnection, hbaseAdapter){};
   }
 
   @Test
-  public void projectIsPopulatedInMutationRequests() throws IOException {
+  public void projectIsPopulatedInMutationRequests()
+      throws IOException, ExecutionException, InterruptedException {
     table.delete(new Delete(Bytes.toBytes("rowKey1")));
 
-    ArgumentCaptor<MutateRowRequest> argument =
-        ArgumentCaptor.forClass(MutateRowRequest.class);
-    verify(mockClient).mutateRow(argument.capture());
+    ArgumentCaptor<RowMutation> argument = ArgumentCaptor.forClass(RowMutation.class);
+    verify(mockBigtableDataClient).mutateRow(argument.capture());
+    RequestContext requestContext =
+        RequestContext.create(InstanceName.of(TEST_PROJECT, TEST_INSTANCE), "");
 
     Assert.assertEquals(
         "projects/testproject/instances/testinstance/tables/testtable",
-        argument.getValue().getTableName());
+        argument.getValue().toProto(requestContext).getTableName());
   }
 
   @Test
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/admin/TestColumnDescriptorAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/admin/TestColumnDescriptorAdapter.java
index 5cb049d50..17f7669a0 100644
--- a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/admin/TestColumnDescriptorAdapter.java
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/admin/TestColumnDescriptorAdapter.java
@@ -15,11 +15,9 @@
  */
 package com.google.cloud.bigtable.hbase.adapters.admin;
 
-import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.intersection;
-import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.maxAge;
-import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.maxVersions;
-import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.union;
+import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES;
 
+import com.google.cloud.bigtable.admin.v2.models.GCRules;
 import java.util.Map;
 import java.util.Set;
 
@@ -36,7 +34,8 @@ import org.junit.runner.RunWith;
 import org.junit.runners.JUnit4;
 
 import com.google.bigtable.admin.v2.ColumnFamily;
-import com.google.bigtable.admin.v2.GcRule;
+import com.google.cloud.bigtable.admin.v2.models.GCRules.GCRule;
+import org.threeten.bp.Duration;
 
 /**
  * Tests for {@link ColumnDescriptorAdapter}.
@@ -44,13 +43,14 @@ import com.google.bigtable.admin.v2.GcRule;
 @RunWith(JUnit4.class)
 public class TestColumnDescriptorAdapter {
 
+  private static final String FAMILY_NAME = "testFamily";
   private ColumnDescriptorAdapter adapter;
   private HColumnDescriptor descriptor;
 
   @Before
   public void setup() {
     adapter = new ColumnDescriptorAdapter();
-    descriptor = new HColumnDescriptor("testFamily");
+    descriptor = new HColumnDescriptor(FAMILY_NAME);
   }
 
   @Rule
@@ -114,14 +114,18 @@ public class TestColumnDescriptorAdapter {
     int ttl = 86400;
     descriptor.setTimeToLive(ttl);
     ColumnFamily result = adapter.adapt(descriptor);
-    Assert.assertEquals(union(maxAge(ttl), maxVersions(1)), result.getGcRule());
+    GCRules.GCRule expected = GCRULES.union().rule(GCRULES.maxAge(Duration.ofSeconds(ttl)))
+            .rule(GCRULES.maxVersions(1));
+    Assert.assertEquals(expected.toProto(), result.getGcRule());
   }
 
   @Test
   public void ttlIsPreservedInColumnFamily() {
     // TTL of 1 day (in microseconds):
+    GCRules.GCRule expected = GCRULES.union().rule(GCRULES.maxAge(Duration.ofSeconds(86400)))
+            .rule(GCRULES.maxVersions(1));
     HColumnDescriptor descriptor =
-        adapter.adapt("family", columnFamily(union(maxAge(86400), maxVersions(1))));
+        adapter.adapt("family", columnFamily(expected));
     Assert.assertEquals(1, descriptor.getMaxVersions());
     Assert.assertEquals(86400, descriptor.getTimeToLive());
   }
@@ -130,12 +134,14 @@ public class TestColumnDescriptorAdapter {
   public void maxVersionsIsPreservedInGcExpression() {
     descriptor.setMaxVersions(10);
     ColumnFamily result = adapter.adapt(descriptor);
-    Assert.assertEquals(maxVersions(10), result.getGcRule());
+    GCRules.GCRule expected = GCRULES.maxVersions(10);
+    Assert.assertEquals(expected.toProto(), result.getGcRule());
   }
 
   @Test
   public void maxVersionsIsPreservedInColumnFamily() {
-    HColumnDescriptor descriptor = adapter.adapt("family", columnFamily(maxVersions(10)));
+    GCRules.GCRule expected = GCRULES.maxVersions(10);
+    HColumnDescriptor descriptor = adapter.adapt("family", columnFamily(expected));
     Assert.assertEquals(10, descriptor.getMaxVersions());
   }
 
@@ -145,12 +151,13 @@ public class TestColumnDescriptorAdapter {
     descriptor.setMinVersions(10);
     descriptor.setTimeToLive(86400); // 1 day in seconds
     ColumnFamily result = adapter.adapt(descriptor);
-    Assert.assertEquals(minMaxRule(10, 86400, 20), result.getGcRule());
+    Assert.assertEquals(minMaxRule(10, 86400, 20).toProto(), result.getGcRule());
   }
 
   @Test
   public void minMaxTtlInColumnFamily() {
-    HColumnDescriptor descriptor = adapter.adapt("family", columnFamily(minMaxRule(10, 86400, 20)));
+    HColumnDescriptor descriptor = adapter.adapt("family",
+            columnFamily(minMaxRule(10, 86400, 20)));
     Assert.assertEquals(20, descriptor.getMaxVersions());
     Assert.assertEquals(10, descriptor.getMinVersions());
     Assert.assertEquals(86400, descriptor.getTimeToLive());
@@ -177,16 +184,38 @@ public class TestColumnDescriptorAdapter {
     Assert.assertEquals(null, ColumnDescriptorAdapter.buildGarbageCollectionRule(descriptor));
   }
 
-  private static ColumnFamily columnFamily(GcRule rule) {
-    return ColumnFamily.newBuilder().setGcRule(rule).build();
+  @Test
+  public void testGCruleMaxVersion(){
+    int ttl = 100;
+    descriptor.setTimeToLive(ttl);
+    descriptor.setMaxVersions(Integer.MAX_VALUE);
+    ColumnFamily result = adapter.adapt(descriptor);
+    GCRule expected = GCRULES.maxAge(Duration.ofSeconds(ttl));
+    Assert.assertEquals(expected.toProto(), result.getGcRule());
+  }
+
+  @Test
+  public void testAdaptWithColumnFamilyForMaxAge(){
+    int ttl = 86400;
+    GCRule maxAgeGCRule = GCRULES.maxAge(Duration.ofSeconds(ttl));
+    ColumnFamily columnFamily = ColumnFamily.newBuilder().setGcRule(maxAgeGCRule.toProto()).build();
+    HColumnDescriptor actual = adapter.adapt(FAMILY_NAME, columnFamily);
+    Assert.assertEquals(ttl, actual.getTimeToLive());
+  }
+
+  private static ColumnFamily columnFamily(GCRule rule) {
+    return ColumnFamily.newBuilder().setGcRule(rule.toProto()).build();
+  }
+
+  private GCRule minMaxRule(int minVersions, int ttl, int maxVersions) {
+    GCRule intersection = GCRULES.intersection().rule(GCRULES.maxAge(Duration.ofSeconds(ttl)))
+            .rule(GCRULES.maxVersions(minVersions));
+    return GCRULES.union().rule(intersection).rule(GCRULES.maxVersions(maxVersions));
   }
 
-  private GcRule minMaxRule(int minVersions, int ttl, int maxVersions) {
-    return union(
-        intersection(
-          maxAge(ttl),
-          maxVersions(minVersions)
-         ),
-        maxVersions(maxVersions));
+  private GCRule minMaxIntersectionRule(int minVersions, int ttl, int maxVersions) {
+    GCRule intersection = GCRULES.intersection().rule(GCRULES.maxAge(Duration.ofSeconds(ttl)))
+            .rule(GCRULES.maxVersions(minVersions));
+    return intersection;
   }
 }
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/admin/TestTableAdapter.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/admin/TestTableAdapter.java
new file mode 100644
index 000000000..27dfc5d20
--- /dev/null
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/adapters/admin/TestTableAdapter.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * 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
+ *
+ *     http://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.hbase.adapters.admin;
+
+import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES;
+import com.google.bigtable.admin.v2.ColumnFamily;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.bigtable.admin.v2.Table;
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.GCRules.GCRule;
+import com.google.cloud.bigtable.grpc.BigtableInstanceName;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class TestTableAdapter {
+
+  private static final String PROJECT_ID = "fakeProject";
+  private static final String INSTANCE_ID = "fakeInstance";
+  private static final String TABLE_ID = "myTable";
+  private static final String INSTANCE_NAME = "projects/" + PROJECT_ID + "/instances/" + INSTANCE_ID;
+  private static final String TABLE_NAME = INSTANCE_NAME + "/tables/" + TABLE_ID;
+  private static final String COLUMN_FAMILY = "myColumnFamily";
+
+  private TableAdapter tableAdapter;
+  private InstanceName instanceName;
+
+  @Before
+  public void setUp(){
+    BigtableInstanceName bigtableInstanceName = new BigtableInstanceName(PROJECT_ID, INSTANCE_ID);
+    tableAdapter = new TableAdapter(bigtableInstanceName);
+    instanceName = InstanceName.of(PROJECT_ID, INSTANCE_ID);
+  }
+
+  @Test
+  public void testAdaptWithHTableDescriptor(){
+    byte[][] splits = new byte[][] {
+            Bytes.toBytes("AAA"),
+            Bytes.toBytes("BBB"),
+            Bytes.toBytes("CCC"),
+    };
+    CreateTableRequest actualRequest =
+            TableAdapter.adapt(new HTableDescriptor(TableName.valueOf(TABLE_ID)), splits);
+
+    CreateTableRequest expectedRequest = CreateTableRequest.of(TABLE_ID);
+    TableAdapter.addSplitKeys(splits, expectedRequest);
+    Assert.assertEquals(
+            expectedRequest.toProto(instanceName),
+            actualRequest.toProto(instanceName));
+  }
+
+
+  @Test
+  public void testAdaptWithHTableDescriptorWhenSplitIsEmpty(){
+    byte[][] splits = new byte[0][0];
+    CreateTableRequest actualRequest =
+            TableAdapter.adapt(new HTableDescriptor(TableName.valueOf(TABLE_ID)), splits);
+
+    CreateTableRequest expectedRequest = CreateTableRequest.of(TABLE_ID);
+    Assert.assertEquals(
+            expectedRequest.toProto(instanceName),
+            actualRequest.toProto(instanceName));
+  }
+
+  @Test
+  public void testAdaptWithColumnDesc(){
+    HColumnDescriptor columnDesc = new HColumnDescriptor(COLUMN_FAMILY);
+    HTableDescriptor desc = new HTableDescriptor(TableName.valueOf(TABLE_ID));
+    CreateTableRequest request = CreateTableRequest.of(TABLE_ID);
+    desc.addFamily(columnDesc);
+
+    TableAdapter.adapt(desc, request);
+
+    GCRule gcRule = ColumnDescriptorAdapter.buildGarbageCollectionRule(columnDesc);
+    CreateTableRequest expected =
+            CreateTableRequest.of(TABLE_ID).addFamily(COLUMN_FAMILY, gcRule);
+    Assert.assertEquals(request.toProto(instanceName), expected.toProto(instanceName));
+  }
+
+
+  @Test
+  public void testAdaptForTable(){
+    //If no GcRule passed to ColumnFamily, then ColumnDescriptorAdapter#buildGarbageCollectionRule
+    //updates maxVersion to Integer.MAX_VALUE
+    GCRule gcRule = GCRULES.maxVersions(1);
+    ColumnFamily columnFamily = ColumnFamily.newBuilder()
+            .setGcRule(gcRule.toProto()).build();
+    Table table = Table.newBuilder()
+            .setName(TABLE_NAME)
+            .putColumnFamilies(COLUMN_FAMILY, columnFamily).build();
+    HTableDescriptor actualTableDesc = tableAdapter.adapt(table);
+
+    HTableDescriptor expected = new HTableDescriptor(TableName.valueOf(TABLE_ID));
+    expected.addFamily(new HColumnDescriptor(COLUMN_FAMILY));
+    Assert.assertEquals(expected, actualTableDesc);
+  }
+}
diff --git a/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/util/TestModifyTableBuilder.java b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/util/TestModifyTableBuilder.java
new file mode 100644
index 000000000..1eee3b634
--- /dev/null
+++ b/bigtable-client-core-parent/bigtable-hbase/src/test/java/com/google/cloud/bigtable/hbase/util/TestModifyTableBuilder.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2018 Google LLC. All Rights Reserved.
+ *
+ * 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
+ *
+ *     http://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.hbase.util;
+
+import static com.google.cloud.bigtable.hbase.adapters.admin.ColumnDescriptorAdapter.buildGarbageCollectionRule;
+
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.cloud.bigtable.admin.v2.models.ModifyColumnFamiliesRequest;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.TableName;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class TestModifyTableBuilder {
+
+  private static final String PROJECT_ID = "fakeProject";
+  private static final String INSTANCE_ID = "fakeInstance";
+  private static final String TABLE_ID = "myTable";
+  private static final String INSTANCE_NAME = "projects/" + PROJECT_ID + "/instances/" + INSTANCE_ID;
+  private static final String TABLE_NAME = INSTANCE_NAME + "/tables/" + TABLE_ID;
+  private static final String COLUMN_FAMILY = "myColumnFamily";
+
+  private ModifyTableBuilder modifyTableBuilder;
+  private InstanceName instanceName;
+
+  @Before
+  public void setUp(){
+    modifyTableBuilder = ModifyTableBuilder.newBuilder(TableName.valueOf(TABLE_ID));
+    instanceName = InstanceName.of(PROJECT_ID, INSTANCE_ID);
+  }
+
+  @Test
+  public void TestBuildModificationForAddFamily(){
+    HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(TABLE_ID));
+    HColumnDescriptor addColumn = new HColumnDescriptor(COLUMN_FAMILY);
+    tableDescriptor.addFamily(addColumn);
+    ModifyTableBuilder actualRequest = ModifyTableBuilder
+            .buildModifications(tableDescriptor, new HTableDescriptor(TableName.valueOf(TABLE_ID)));
+
+    ModifyColumnFamiliesRequest expectedRequest = ModifyColumnFamiliesRequest.of(TABLE_ID)
+            .addFamily(COLUMN_FAMILY, buildGarbageCollectionRule(addColumn));
+
+    Assert.assertEquals(expectedRequest.toProto(instanceName),
+            actualRequest.build().toProto(instanceName));
+  }
+
+  @Test
+  public void TestBuildModificationForUpdateFamily(){
+    HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(TABLE_ID));
+    HColumnDescriptor addColumn = new HColumnDescriptor(COLUMN_FAMILY);
+    tableDescriptor.addFamily(addColumn);
+    ModifyTableBuilder actualRequest = ModifyTableBuilder
+            .buildModifications(tableDescriptor, new HTableDescriptor(tableDescriptor));
+
+    ModifyColumnFamiliesRequest expectedRequest = ModifyColumnFamiliesRequest.of(TABLE_ID)
+            .updateFamily(COLUMN_FAMILY, buildGarbageCollectionRule(addColumn));
+
+    Assert.assertEquals(expectedRequest.toProto(instanceName),
+            actualRequest.build().toProto(instanceName));
+  }
+
+  @Test
+  public void TestBuildModificationForDropFamily(){
+    String NEW_COLUMN_FAMILY = "anotherColumnFamily";
+    HTableDescriptor tableDescriptor = new HTableDescriptor(TableName.valueOf(TABLE_ID));
+    HColumnDescriptor addColumn = new HColumnDescriptor(COLUMN_FAMILY);
+    tableDescriptor.addFamily(addColumn);
+    HTableDescriptor newTableDesc = new HTableDescriptor(TableName.valueOf(TABLE_ID));
+    HColumnDescriptor newColumnDesc = new HColumnDescriptor(NEW_COLUMN_FAMILY);
+    newTableDesc.addFamily(newColumnDesc);
+    ModifyTableBuilder actualRequest = ModifyTableBuilder
+            .buildModifications(tableDescriptor, newTableDesc);
+
+    ModifyColumnFamiliesRequest expectedRequest = ModifyColumnFamiliesRequest.of(TABLE_ID)
+            .addFamily(COLUMN_FAMILY, buildGarbageCollectionRule(addColumn))
+            .dropFamily(NEW_COLUMN_FAMILY);
+
+    Assert.assertEquals(expectedRequest.toProto(instanceName),
+            actualRequest.build().toProto(instanceName));
+  }
+}
diff --git a/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/test/java/com/google/cloud/bigtable/hbase/com/google/cloud/bigtable/hbase2_x/adapters/admin/TestTableAdapter2x.java b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/test/java/com/google/cloud/bigtable/hbase/com/google/cloud/bigtable/hbase2_x/adapters/admin/TestTableAdapter2x.java
new file mode 100644
index 000000000..fafdee640
--- /dev/null
+++ b/bigtable-hbase-2.x-parent/bigtable-hbase-2.x/src/test/java/com/google/cloud/bigtable/hbase/com/google/cloud/bigtable/hbase2_x/adapters/admin/TestTableAdapter2x.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018 Google Inc. All Rights Reserved.
+ *
+ * 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
+ *
+ *     http://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.hbase.com.google.cloud.bigtable.hbase2_x.adapters.admin;
+
+import static com.google.cloud.bigtable.admin.v2.models.GCRules.GCRULES;
+
+import com.google.bigtable.admin.v2.ColumnFamily;
+import com.google.bigtable.admin.v2.InstanceName;
+import com.google.bigtable.admin.v2.Table;
+import com.google.cloud.bigtable.admin.v2.models.CreateTableRequest;
+import com.google.cloud.bigtable.admin.v2.models.GCRules;
+import com.google.cloud.bigtable.config.BigtableOptions;
+import com.google.cloud.bigtable.hbase.adapters.admin.TableAdapter;
+import com.google.cloud.bigtable.hbase2_x.adapters.admin.TableAdapter2x;
+import org.apache.hadoop.hbase.HColumnDescriptor;
+import org.apache.hadoop.hbase.HTableDescriptor;
+import org.apache.hadoop.hbase.TableName;
+import org.apache.hadoop.hbase.client.*;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class TestTableAdapter2x {
+
+  private static final String PROJECT_ID = "fakeProject";
+  private static final String INSTANCE_ID = "fakeInstance";
+  private static final String TABLE_ID = "myTable";
+  private static final String INSTANCE_NAME = "projects/" + PROJECT_ID + "/instances/" + INSTANCE_ID;
+  private static final String TABLE_NAME = INSTANCE_NAME + "/tables/" + TABLE_ID;
+  private static final String COLUMN_FAMILY = "myColumnFamily";
+
+  private TableAdapter2x tableAdapter2x;
+  private InstanceName instanceName;
+
+  @Before
+  public void setUp(){
+    BigtableOptions bigtableOptions = BigtableOptions.builder().setProjectId(PROJECT_ID)
+            .setInstanceId(INSTANCE_ID).build();
+    tableAdapter2x = new TableAdapter2x(bigtableOptions);
+    instanceName = InstanceName.of(PROJECT_ID, INSTANCE_ID);
+  }
+
+  @Test
+  public void testAdaptWithSplitKeys(){
+    byte[][] splits = new byte[][] {
+            Bytes.toBytes("AAA"),
+            Bytes.toBytes("BBB"),
+            Bytes.toBytes("CCC"),
+    };
+    TableDescriptor desc = TableDescriptorBuilder.newBuilder(TableName.valueOf(TABLE_ID)).build();
+    CreateTableRequest actualRequest = TableAdapter2x.adapt(desc, splits);
+
+    CreateTableRequest expectedRequest = CreateTableRequest.of(TABLE_ID);
+    TableAdapter.addSplitKeys(splits, expectedRequest);
+    Assert.assertEquals(
+            expectedRequest.toProto(instanceName),
+            actualRequest.toProto(instanceName));
+  }
+
+  @Test
+  public void testAdaptWithTable(){
+    //If no GcRule passed to ColumnFamily, then ColumnDescriptorAdapter#buildGarbageCollectionRule
+    //updates maxVersion to Integer.MAX_VALUE
+    int maxVersion = 1;
+    GCRules.GCRule gcRule = GCRULES.maxVersions(maxVersion);
+    ColumnFamily columnFamily = ColumnFamily.newBuilder()
+            .setGcRule(gcRule.toProto()).build();
+    Table table = Table.newBuilder()
+            .setName(TABLE_NAME)
+            .putColumnFamilies(COLUMN_FAMILY, columnFamily).build();
+    TableDescriptor actualTableDesc = tableAdapter2x.adapt(table);
+
+    TableDescriptor expected = new HTableDescriptor(TableName.valueOf(TABLE_ID))
+            .addFamily(new HColumnDescriptor(COLUMN_FAMILY));
+
+    Assert.assertEquals(expected, actualTableDesc);
+  }
+
+  @Test
+  public void testHColumnDescriptorAdapter(){
+    ColumnFamilyDescriptor columnFamilyDesc = ColumnFamilyDescriptorBuilder.of(COLUMN_FAMILY);
+    HColumnDescriptor actualDesc = TableAdapter2x.toHColumnDescriptor(columnFamilyDesc);
+    HColumnDescriptor columnDes = new HColumnDescriptor(COLUMN_FAMILY);
+
+    Assert.assertEquals(columnDes, actualDesc);
+  }
+}