Repository: apache/incubator-fluo (java)

Issue:
Use Charsequence in API
In methods that currently take String as a parameter in the API package, it would be better to take Charsequence.  Since String can be assigned to Charsequence this will support all existing code, plus more like the assignment of StringBuffer etc.

For example we can change

```java
   Bytes.of(String s)
```

to 

```java
   Bytes.of(Charsequence s)
```

Methods that return String should not be changed.  The following is take from [a stackoverflow post](http://stackoverflow.com/questions/11323962/exact-difference-between-charsequence-and-string-in-java) and I think this makes sense.


> Any method which accepts a CharSequence can operate on all of these equally well. Any method which only accepts a String will require conversion. So using CharSequence as an argument type in all the places where you don't care about the internals is prudent. However you should use String as a return type if you actually return a String, because that avoids possible conversions of returned values if the calling method actually does require a String.


It would be ok for now to change the implementation to call `cs.toString().getBytes()` where `cs` is a CharSequence.  Once the API change is made, its easy to optimize the implementation in the future w/o impacting users.

Pull request:
closes #714 use CharSequence in API

Patch:
diff --git a/modules/accumulo/src/main/java/org/apache/fluo/accumulo/util/ByteArrayUtil.java b/modules/accumulo/src/main/java/org/apache/fluo/accumulo/util/ByteArrayUtil.java
index 72c00602..33dc796a 100644
--- a/modules/accumulo/src/main/java/org/apache/fluo/accumulo/util/ByteArrayUtil.java
+++ b/modules/accumulo/src/main/java/org/apache/fluo/accumulo/util/ByteArrayUtil.java
@@ -123,7 +123,7 @@ public class ByteArrayUtil {
     try (InputStream in = new ByteArrayInputStream(b)) {
       DataInputStream dis = new DataInputStream(in);
 
-      BytesBuilder builder = Bytes.newBuilder(b.length);
+      BytesBuilder builder = Bytes.builder(b.length);
 
       while (true) {
         int len = WritableUtils.readVInt(dis);
diff --git a/modules/api/src/main/java/org/apache/fluo/api/client/SnapshotBase.java b/modules/api/src/main/java/org/apache/fluo/api/client/SnapshotBase.java
index 4dcc84da..b0e61f2a 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/client/SnapshotBase.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/client/SnapshotBase.java
@@ -105,19 +105,19 @@ public interface SnapshotBase {
    * Wrapper for {@link #get(Collection, Set)} that uses Strings. All strings are encoded and
    * decoded using UTF-8.
    */
-  Map<String, Map<Column, String>> gets(Collection<String> rows, Set<Column> columns);
+  Map<String, Map<Column, String>> gets(Collection<? extends CharSequence> rows, Set<Column> columns);
 
   /**
    * Wrapper for {@link #get(Bytes, Column)} that uses Strings. All strings are encoded and decoded
    * using UTF-8.
    */
-  String gets(String row, Column column);
+  String gets(CharSequence row, Column column);
 
   /**
    * Wrapper for {@link #get(Bytes, Set)} that uses Strings. All strings are encoded and decoded
    * using UTF-8.
    */
-  Map<Column, String> gets(String row, Set<Column> columns);
+  Map<Column, String> gets(CharSequence row, Set<Column> columns);
 
   /**
    * @return transactions start timestamp allocated from Oracle.
diff --git a/modules/api/src/main/java/org/apache/fluo/api/client/TransactionBase.java b/modules/api/src/main/java/org/apache/fluo/api/client/TransactionBase.java
index c9362daa..8167b72f 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/client/TransactionBase.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/client/TransactionBase.java
@@ -36,7 +36,7 @@ public interface TransactionBase extends SnapshotBase {
    * Wrapper for {@link #delete(Bytes, Column)} that uses Strings. All String are encoded using
    * UTF-8.
    */
-  void delete(String row, Column col);
+  void delete(CharSequence row, Column col);
 
   /**
    * Sets a value (in {@link Bytes}) at the given row and {@link Column}
@@ -47,7 +47,7 @@ public interface TransactionBase extends SnapshotBase {
    * Wrapper for {@link #set(Bytes, Column, Bytes)} that uses Strings. All String are encoded using
    * UTF-8.
    */
-  void set(String row, Column col, String value) throws AlreadySetException;
+  void set(CharSequence row, Column col, CharSequence value) throws AlreadySetException;
 
   /**
    * Sets a weak notification at the given row and {@link Column}
@@ -58,5 +58,5 @@ public interface TransactionBase extends SnapshotBase {
    * Wrapper for {@link #setWeakNotification(Bytes, Column)} that uses Strings. All String are
    * encoded using UTF-8.
    */
-  void setWeakNotification(String row, Column col);
+  void setWeakNotification(CharSequence row, Column col);
 }
diff --git a/modules/api/src/main/java/org/apache/fluo/api/data/Bytes.java b/modules/api/src/main/java/org/apache/fluo/api/data/Bytes.java
index 6c4a3103..29027726 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/data/Bytes.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/data/Bytes.java
@@ -22,6 +22,7 @@ import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.Serializable;
 import java.nio.ByteBuffer;
+import java.nio.CharBuffer;
 import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.Arrays;
@@ -276,6 +277,31 @@ public final class Bytes implements Comparable<Bytes>, Serializable {
     return new Bytes(data);
   }
 
+  /**
+   * Creates a Bytes object by copying the data of the CharSequence and encoding it using UTF-8.
+   */
+  public static final Bytes of(CharSequence cs) {
+    if (cs instanceof String) {
+      return of((String) cs);
+    }
+
+    Objects.requireNonNull(cs);
+    if (cs.length() == 0) {
+      return EMPTY;
+    }
+
+    ByteBuffer bb = StandardCharsets.UTF_8.encode(CharBuffer.wrap(cs));
+
+    if (bb.hasArray()) {
+      // this byte buffer has never escaped so can use its byte array directly
+      return new Bytes(bb.array(), bb.position() + bb.arrayOffset(), bb.limit());
+    } else {
+      byte[] data = new byte[bb.remaining()];
+      bb.get(data);
+      return new Bytes(data);
+    }
+  }
+
   /**
    * Creates a Bytes object by copying the value of the given String
    */
@@ -332,6 +358,21 @@ public final class Bytes implements Comparable<Bytes>, Serializable {
       }
     }
 
+    public BytesBuilder append(CharSequence cs) {
+      if (cs instanceof String) {
+        return append((String) cs);
+      }
+
+
+      ByteBuffer bb = StandardCharsets.UTF_8.encode(CharBuffer.wrap(cs));
+
+      int length = bb.remaining();
+      ensureCapacity(len + length);
+      bb.get(ba, len, length);
+      len += length;
+      return this;
+    }
+
     /**
      * Converts string to bytes using UTF-8 encoding and appends bytes.
      *
@@ -440,14 +481,14 @@ public final class Bytes implements Comparable<Bytes>, Serializable {
   /**
    * Provides an efficient and reusable way to build immutable Bytes objects.
    */
-  public static BytesBuilder newBuilder() {
+  public static BytesBuilder builder() {
     return new BytesBuilder();
   }
 
   /**
    * @param initialCapacity The initial size of the byte builders internal array.
    */
-  public static BytesBuilder newBuilder(int initialCapacity) {
+  public static BytesBuilder builder(int initialCapacity) {
     return new BytesBuilder(initialCapacity);
   }
 }
diff --git a/modules/api/src/main/java/org/apache/fluo/api/data/Column.java b/modules/api/src/main/java/org/apache/fluo/api/data/Column.java
index fe0c6f06..008e04c3 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/data/Column.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/data/Column.java
@@ -52,7 +52,7 @@ public final class Column implements Comparable<Column>, Serializable {
   /**
    * Creates Column with only a family. String parameter will be encoded as UTF-8.
    */
-  public Column(String family) {
+  public Column(CharSequence family) {
     this(Bytes.of(family));
   }
 
@@ -69,7 +69,7 @@ public final class Column implements Comparable<Column>, Serializable {
   /**
    * Creates Column with a family and qualifier. String parameters will be encoded as UTF-8.
    */
-  public Column(String family, String qualifier) {
+  public Column(CharSequence family, CharSequence qualifier) {
     this(Bytes.of(family), Bytes.of(qualifier));
   }
 
@@ -89,7 +89,7 @@ public final class Column implements Comparable<Column>, Serializable {
    * Creates Column with family, qualifier, and visibility. String parameters will be encoded as
    * UTF-8.
    */
-  public Column(String family, String qualifier, String visibility) {
+  public Column(CharSequence family, CharSequence qualifier, CharSequence visibility) {
     this(Bytes.of(family), Bytes.of(qualifier), Bytes.of(visibility));
   }
 
diff --git a/modules/api/src/main/java/org/apache/fluo/api/data/ColumnValue.java b/modules/api/src/main/java/org/apache/fluo/api/data/ColumnValue.java
index 63f8c675..9d3d0544 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/data/ColumnValue.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/data/ColumnValue.java
@@ -33,7 +33,7 @@ public final class ColumnValue implements Serializable, Comparable<ColumnValue>
     this.val = val;
   }
 
-  public ColumnValue(Column col, String val) {
+  public ColumnValue(Column col, CharSequence val) {
     this.column = col;
     this.val = Bytes.of(val);
   }
diff --git a/modules/api/src/main/java/org/apache/fluo/api/data/RowColumn.java b/modules/api/src/main/java/org/apache/fluo/api/data/RowColumn.java
index d9990a20..078ad5c2 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/data/RowColumn.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/data/RowColumn.java
@@ -52,7 +52,7 @@ public final class RowColumn implements Comparable<RowColumn>, Serializable {
    *
    * @param row (will be UTF-8 encoded)
    */
-  public RowColumn(String row) {
+  public RowColumn(CharSequence row) {
     this(Bytes.of(row));
   }
 
@@ -75,7 +75,7 @@ public final class RowColumn implements Comparable<RowColumn>, Serializable {
    * @param row Row String (will be UTF-8 encoded)
    * @param col Column
    */
-  public RowColumn(String row, Column col) {
+  public RowColumn(CharSequence row, Column col) {
     this(Bytes.of(row), col);
   }
 
diff --git a/modules/api/src/main/java/org/apache/fluo/api/data/RowColumnValue.java b/modules/api/src/main/java/org/apache/fluo/api/data/RowColumnValue.java
index 62968be0..455271ee 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/data/RowColumnValue.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/data/RowColumnValue.java
@@ -40,7 +40,7 @@ public final class RowColumnValue implements Comparable<RowColumnValue>, Seriali
    * @param row (will be UTF-8 encoded)
    * @param val (will be UTF-8 encoded)
    */
-  public RowColumnValue(String row, Column col, String val) {
+  public RowColumnValue(CharSequence row, Column col, CharSequence val) {
     this.row = Bytes.of(row);
     this.col = col;
     this.val = Bytes.of(val);
diff --git a/modules/api/src/main/java/org/apache/fluo/api/data/Span.java b/modules/api/src/main/java/org/apache/fluo/api/data/Span.java
index 5d668bb3..603ce642 100644
--- a/modules/api/src/main/java/org/apache/fluo/api/data/Span.java
+++ b/modules/api/src/main/java/org/apache/fluo/api/data/Span.java
@@ -130,7 +130,8 @@ public final class Span implements Serializable {
    * @param endRow End row
    * @param endRowInclusive End row inclusive
    */
-  public Span(String startRow, boolean startRowInclusive, String endRow, boolean endRowInclusive) {
+  public Span(CharSequence startRow, boolean startRowInclusive, CharSequence endRow,
+      boolean endRowInclusive) {
     this(Bytes.of(startRow), startRowInclusive, Bytes.of(endRow), endRowInclusive);
   }
 
@@ -210,7 +211,7 @@ public final class Span implements Serializable {
   /**
    * Creates a Span that covers an exact row. String parameters will be encoded as UTF-8
    */
-  public static Span exact(String row) {
+  public static Span exact(CharSequence row) {
     Objects.requireNonNull(row);
     return exact(Bytes.of(row));
   }
@@ -232,7 +233,7 @@ public final class Span implements Serializable {
    * method can be constructed without a qualifier or visibility to create a Span at the family or
    * qualifier level. String parameters will be encoded as UTF-8
    */
-  public static Span exact(String row, Column col) {
+  public static Span exact(CharSequence row, Column col) {
     Objects.requireNonNull(row);
     Objects.requireNonNull(col);
     return exact(Bytes.of(row), col);
@@ -272,7 +273,7 @@ public final class Span implements Serializable {
    * Returns a Span that covers all rows beginning with a prefix String parameters will be encoded
    * as UTF-8
    */
-  public static Span prefix(String rowPrefix) {
+  public static Span prefix(CharSequence rowPrefix) {
     Objects.requireNonNull(rowPrefix);
     return prefix(Bytes.of(rowPrefix));
   }
@@ -317,7 +318,7 @@ public final class Span implements Serializable {
    * create a prefix Span at the family or qualifier level. String parameters will be encoded as
    * UTF-8
    */
-  public static Span prefix(String row, Column colPrefix) {
+  public static Span prefix(CharSequence row, Column colPrefix) {
     Objects.requireNonNull(row);
     Objects.requireNonNull(colPrefix);
     return prefix(Bytes.of(row), colPrefix);
@@ -358,7 +359,7 @@ public final class Span implements Serializable {
     /**
      * Build start of Span starting with row (will be encoded UTF-8)
      */
-    public StartCFBuilder startRow(String row) {
+    public StartCFBuilder startRow(CharSequence row) {
       return startRow(Bytes.of(row));
     }
 
@@ -374,7 +375,7 @@ public final class Span implements Serializable {
     /**
      * Build end of Span starting with row (will be encoded UTF-8)
      */
-    public EndCFBuilder endRow(String row) {
+    public EndCFBuilder endRow(CharSequence row) {
       return endRow(Bytes.of(row));
     }
 
@@ -404,7 +405,7 @@ public final class Span implements Serializable {
     /**
      * Build Span end starting with row (will be encoded UTF-8)
      */
-    public EndCFBuilder endRow(String row) {
+    public EndCFBuilder endRow(CharSequence row) {
       return endRow(Bytes.of(row));
     }
 
@@ -468,7 +469,7 @@ public final class Span implements Serializable {
     /**
      * Add column visibility (will be encoded UTF-8) to Span start
      */
-    public StartBuilder vis(String cv) {
+    public StartBuilder vis(CharSequence cv) {
       return vis(Bytes.of(cv));
     }
   }
@@ -493,7 +494,7 @@ public final class Span implements Serializable {
     /**
      * Add column qualifier (will be encoded UTF-8) to Span start
      */
-    public StartCVBuilder qual(String cq) {
+    public StartCVBuilder qual(CharSequence cq) {
       return qual(Bytes.of(cq));
     }
   }
@@ -518,7 +519,7 @@ public final class Span implements Serializable {
     /**
      * Add column family (will be encoded UTF-8) to Span start
      */
-    public StartCQBuilder fam(String cf) {
+    public StartCQBuilder fam(CharSequence cf) {
       return fam(Bytes.of(cf));
     }
   }
@@ -543,7 +544,7 @@ public final class Span implements Serializable {
     /**
      * Add column visibility (will be encoded UTF-8) to Span end
      */
-    public EndBuilder vis(String cv) {
+    public EndBuilder vis(CharSequence cv) {
       return vis(Bytes.of(cv));
     }
   }
@@ -568,7 +569,7 @@ public final class Span implements Serializable {
     /**
      * Add column qualifier (will be encoded UTF-8) to Span end
      */
-    public EndCVBuilder qual(String cq) {
+    public EndCVBuilder qual(CharSequence cq) {
       return qual(Bytes.of(cq));
     }
   }
@@ -593,7 +594,7 @@ public final class Span implements Serializable {
     /**
      * Add column family (will be encoded UTF-8) to an Span end
      */
-    public EndCQBuilder fam(String cf) {
+    public EndCQBuilder fam(CharSequence cf) {
       return fam(Bytes.of(cf));
     }
   }
diff --git a/modules/core/src/main/java/org/apache/fluo/core/impl/TransactionImpl.java b/modules/core/src/main/java/org/apache/fluo/core/impl/TransactionImpl.java
index bbda32a9..d66df36e 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/impl/TransactionImpl.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/impl/TransactionImpl.java
@@ -307,7 +307,7 @@ public class TransactionImpl implements AsyncTransaction, Snapshot {
   }
 
   @Override
-  public void set(String row, Column col, String value) throws AlreadySetException {
+  public void set(CharSequence row, Column col, CharSequence value) throws AlreadySetException {
     set(Bytes.of(row), col, Bytes.of(value));
   }
 
@@ -333,7 +333,7 @@ public class TransactionImpl implements AsyncTransaction, Snapshot {
   }
 
   @Override
-  public void setWeakNotification(String row, Column col) {
+  public void setWeakNotification(CharSequence row, Column col) {
     setWeakNotification(Bytes.of(row), col);
   }
 
@@ -346,7 +346,7 @@ public class TransactionImpl implements AsyncTransaction, Snapshot {
   }
 
   @Override
-  public void delete(String row, Column col) {
+  public void delete(CharSequence row, Column col) {
     delete(Bytes.of(row), col);
   }
 
@@ -659,17 +659,18 @@ public class TransactionImpl implements AsyncTransaction, Snapshot {
   }
 
   @Override
-  public String gets(String row, Column column) {
+  public String gets(CharSequence row, Column column) {
     return TxStringUtil.gets(this, row, column);
   }
 
   @Override
-  public Map<Column, String> gets(String row, Set<Column> columns) {
+  public Map<Column, String> gets(CharSequence row, Set<Column> columns) {
     return TxStringUtil.gets(this, row, columns);
   }
 
   @Override
-  public Map<String, Map<Column, String>> gets(Collection<String> rows, Set<Column> columns) {
+  public Map<String, Map<Column, String>> gets(Collection<? extends CharSequence> rows,
+      Set<Column> columns) {
     return TxStringUtil.gets(this, rows, columns);
   }
 
diff --git a/modules/core/src/main/java/org/apache/fluo/core/impl/TxStringUtil.java b/modules/core/src/main/java/org/apache/fluo/core/impl/TxStringUtil.java
index ec1759a0..c9874c0b 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/impl/TxStringUtil.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/impl/TxStringUtil.java
@@ -38,7 +38,7 @@ public class TxStringUtil {
     return ret;
   }
 
-  public static String gets(SnapshotBase snapshot, String row, Column column) {
+  public static String gets(SnapshotBase snapshot, CharSequence row, Column column) {
     Bytes val = snapshot.get(Bytes.of(row), column);
     if (val == null) {
       return null;
@@ -46,13 +46,14 @@ public class TxStringUtil {
     return val.toString();
   }
 
-  public static Map<Column, String> gets(SnapshotBase snapshot, String row, Set<Column> columns) {
+  public static Map<Column, String> gets(SnapshotBase snapshot, CharSequence row,
+      Set<Column> columns) {
     Map<Column, Bytes> values = snapshot.get(Bytes.of(row), columns);
     return Maps.transformValues(values, b -> b.toString());
   }
 
   public static Map<String, Map<Column, String>> gets(SnapshotBase snapshot,
-      Collection<String> rows, Set<Column> columns) {
+      Collection<? extends CharSequence> rows, Set<Column> columns) {
     return transform(snapshot.get(Collections2.transform(rows, s -> Bytes.of(s)), columns));
   }
 
diff --git a/modules/core/src/main/java/org/apache/fluo/core/log/TracingTransaction.java b/modules/core/src/main/java/org/apache/fluo/core/log/TracingTransaction.java
index ab2e4294..34cd61ed 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/log/TracingTransaction.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/log/TracingTransaction.java
@@ -169,7 +169,7 @@ public class TracingTransaction implements AsyncTransaction, Snapshot {
   }
 
   @Override
-  public void setWeakNotification(String row, Column col) {
+  public void setWeakNotification(CharSequence row, Column col) {
     setWeakNotification(Bytes.of(row), col);
   }
 
@@ -182,7 +182,7 @@ public class TracingTransaction implements AsyncTransaction, Snapshot {
   }
 
   @Override
-  public void set(String row, Column col, String value) throws AlreadySetException {
+  public void set(CharSequence row, Column col, CharSequence value) throws AlreadySetException {
     set(Bytes.of(row), col, Bytes.of(value));
   }
 
@@ -195,7 +195,7 @@ public class TracingTransaction implements AsyncTransaction, Snapshot {
   }
 
   @Override
-  public void delete(String row, Column col) {
+  public void delete(CharSequence row, Column col) {
     delete(Bytes.of(row), col);
   }
 
@@ -255,17 +255,18 @@ public class TracingTransaction implements AsyncTransaction, Snapshot {
   }
 
   @Override
-  public String gets(String row, Column column) {
+  public String gets(CharSequence row, Column column) {
     return TxStringUtil.gets(this, row, column);
   }
 
   @Override
-  public Map<Column, String> gets(String row, Set<Column> columns) {
+  public Map<Column, String> gets(CharSequence row, Set<Column> columns) {
     return TxStringUtil.gets(this, row, columns);
   }
 
   @Override
-  public Map<String, Map<Column, String>> gets(Collection<String> rows, Set<Column> columns) {
+  public Map<String, Map<Column, String>> gets(Collection<? extends CharSequence> rows,
+      Set<Column> columns) {
     return TxStringUtil.gets(this, rows, columns);
   }
 
diff --git a/modules/core/src/main/java/org/apache/fluo/core/util/ColumnUtil.java b/modules/core/src/main/java/org/apache/fluo/core/util/ColumnUtil.java
index 9ffc94a4..b934f0bb 100644
--- a/modules/core/src/main/java/org/apache/fluo/core/util/ColumnUtil.java
+++ b/modules/core/src/main/java/org/apache/fluo/core/util/ColumnUtil.java
@@ -109,7 +109,7 @@ public class ColumnUtil {
   }
 
   public static Column readColumn(DataInputStream in) throws IOException {
-    BytesBuilder bb = Bytes.newBuilder();
+    BytesBuilder bb = Bytes.builder();
     Bytes family = ByteUtil.read(bb, in);
     Bytes qualifier = ByteUtil.read(bb, in);
     Bytes visibility = ByteUtil.read(bb, in);


Test patch:
diff --git a/modules/api/src/test/java/org/apache/fluo/api/data/BytesBuilderTest.java b/modules/api/src/test/java/org/apache/fluo/api/data/BytesBuilderTest.java
index 538eda64..8c448618 100644
--- a/modules/api/src/test/java/org/apache/fluo/api/data/BytesBuilderTest.java
+++ b/modules/api/src/test/java/org/apache/fluo/api/data/BytesBuilderTest.java
@@ -28,12 +28,12 @@ import org.junit.Test;
 public class BytesBuilderTest {
   @Test
   public void testBasic() {
-    BytesBuilder bb = Bytes.newBuilder();
+    BytesBuilder bb = Bytes.builder();
 
     Bytes bytes1 = bb.append(new byte[] {'a', 'b'}).append("cd").append(Bytes.of("ef")).toBytes();
     Assert.assertEquals(Bytes.of("abcdef"), bytes1);
 
-    bb = Bytes.newBuilder();
+    bb = Bytes.builder();
     Bytes bytes2 = bb.append(Bytes.of("ab")).append("cd").append(new byte[] {'e', 'f'}).toBytes();
     Assert.assertEquals(Bytes.of("abcdef"), bytes2);
   }
@@ -43,7 +43,7 @@ public class BytesBuilderTest {
 
     ByteArrayInputStream bais =
         new ByteArrayInputStream("abcdefg".getBytes(StandardCharsets.UTF_8));
-    BytesBuilder bb = Bytes.newBuilder();
+    BytesBuilder bb = Bytes.builder();
 
     bb.append(bais, 2);
     bb.append(bais, 3);
@@ -55,7 +55,7 @@ public class BytesBuilderTest {
   public void testByteBuffer() {
     ByteBuffer buffer = ByteBuffer.wrap("abcdefg".getBytes(StandardCharsets.UTF_8));
 
-    BytesBuilder bb = Bytes.newBuilder();
+    BytesBuilder bb = Bytes.builder();
 
     bb.append(buffer);
     bb.append(buffer);
@@ -68,7 +68,7 @@ public class BytesBuilderTest {
 
   @Test
   public void testSetLength() {
-    BytesBuilder bb = Bytes.newBuilder();
+    BytesBuilder bb = Bytes.builder();
 
     Bytes bytes1 = bb.append(new byte[] {'a', 'b'}).append("cd").append(Bytes.of("ef")).toBytes();
     Assert.assertEquals(Bytes.of("abcdef"), bytes1);
@@ -91,7 +91,7 @@ public class BytesBuilderTest {
 
   @Test
   public void testSingleByte() {
-    BytesBuilder bb = Bytes.newBuilder();
+    BytesBuilder bb = Bytes.builder();
 
     bb.append('c');
     bb.append(0);
@@ -105,7 +105,7 @@ public class BytesBuilderTest {
 
   @Test
   public void testArraySection() {
-    BytesBuilder bb = Bytes.newBuilder();
+    BytesBuilder bb = Bytes.builder();
 
     byte[] testing = new byte[] {'a', 'b', 'c', 'd', 'e'};
 
@@ -122,9 +122,9 @@ public class BytesBuilderTest {
 
     // test appending 3 chars at a time
     StringBuilder sb = new StringBuilder();
-    BytesBuilder bb = Bytes.newBuilder();
-    BytesBuilder bb2 = Bytes.newBuilder();
-    BytesBuilder bb3 = Bytes.newBuilder();
+    BytesBuilder bb = Bytes.builder();
+    BytesBuilder bb2 = Bytes.builder();
+    BytesBuilder bb3 = Bytes.builder();
     int m = 19;
     for (int i = 0; i < 100; i++) {
       // produce a deterministic non repeating pattern
@@ -143,8 +143,8 @@ public class BytesBuilderTest {
 
     // test appending one char at a time
     sb.setLength(0);
-    bb = Bytes.newBuilder();
-    bb2 = Bytes.newBuilder();
+    bb = Bytes.builder();
+    bb2 = Bytes.builder();
     bb3.setLength(0);
     for (int i = 0; i < 500; i++) {
       // produce a deterministic non repeating pattern
@@ -161,4 +161,21 @@ public class BytesBuilderTest {
     Assert.assertEquals(Bytes.of(sb.toString()), bb2.toBytes());
     Assert.assertEquals(Bytes.of(sb.toString()), bb3.toBytes());
   }
+
+  @Test
+  public void testCharSequence() {
+    AsciiSequence cs1 = new AsciiSequence("abc123");
+    AsciiSequence cs2 = new AsciiSequence("xyz789");
+
+
+    Bytes b3 = Bytes.builder().append(cs1).append(":").append(cs2).toBytes();
+
+    Assert.assertEquals("abc123:xyz789", b3.toString());
+
+    Bytes b4 =
+        Bytes.builder().append((CharSequence) "abc123").append(":").append((CharSequence) "xyz789")
+            .toBytes();
+
+    Assert.assertEquals("abc123:xyz789", b4.toString());
+  }
 }
diff --git a/modules/api/src/test/java/org/apache/fluo/api/data/BytesTest.java b/modules/api/src/test/java/org/apache/fluo/api/data/BytesTest.java
index 56c33f69..8a3baf28 100644
--- a/modules/api/src/test/java/org/apache/fluo/api/data/BytesTest.java
+++ b/modules/api/src/test/java/org/apache/fluo/api/data/BytesTest.java
@@ -26,6 +26,43 @@ import org.apache.fluo.api.data.Bytes;
 import org.junit.Assert;
 import org.junit.Test;
 
+class AsciiSequence implements CharSequence {
+
+
+  private final int len;
+  private final int offset;
+  private final byte[] chars;
+
+  public AsciiSequence(byte[] chars, int offset, int len) {
+    this.len = len;
+    this.offset = offset;
+    this.chars = chars;
+  }
+
+  public AsciiSequence(String s) {
+    chars = s.getBytes(StandardCharsets.US_ASCII);
+    len = chars.length;
+    offset = 0;
+  }
+
+  @Override
+  public int length() {
+    return len;
+  }
+
+  @Override
+  public char charAt(int index) {
+    return (char) chars[index];
+  }
+
+  @Override
+  public CharSequence subSequence(int start, int end) {
+    return new AsciiSequence(chars, offset + start, end - start);
+  }
+
+}
+
+
 /**
  * Unit test for {@link Bytes}
  */
@@ -168,4 +205,20 @@ public class BytesTest {
     } catch (IndexOutOfBoundsException e) {
     }
   }
+
+  @Test
+  public void testCharSequence() {
+    AsciiSequence cs1 = new AsciiSequence("abc123");
+
+    Bytes b1 = Bytes.of(cs1);
+
+    Assert.assertEquals("abc123", b1.toString());
+
+    Bytes b3 = Bytes.of((CharSequence) "abc123");
+
+    Assert.assertEquals("abc123", b3.toString());
+
+    AsciiSequence cs2 = new AsciiSequence("");
+    Assert.assertSame(Bytes.EMPTY, Bytes.of(cs2));
+  }
 }
diff --git a/modules/integration/src/test/java/org/apache/fluo/integration/TestTransaction.java b/modules/integration/src/test/java/org/apache/fluo/integration/TestTransaction.java
index 8661f450..c4c20889 100644
--- a/modules/integration/src/test/java/org/apache/fluo/integration/TestTransaction.java
+++ b/modules/integration/src/test/java/org/apache/fluo/integration/TestTransaction.java
@@ -160,7 +160,7 @@ public class TestTransaction implements TransactionBase {
   }
 
   @Override
-  public void delete(String row, Column col) {
+  public void delete(CharSequence row, Column col) {
     tx.delete(row, col);
   }
 
@@ -170,7 +170,7 @@ public class TestTransaction implements TransactionBase {
   }
 
   @Override
-  public void set(String row, Column col, String value) throws AlreadySetException {
+  public void set(CharSequence row, Column col, CharSequence value) throws AlreadySetException {
     tx.set(row, col, value);
   }
 
@@ -180,7 +180,7 @@ public class TestTransaction implements TransactionBase {
   }
 
   @Override
-  public void setWeakNotification(String row, Column col) {
+  public void setWeakNotification(CharSequence row, Column col) {
     tx.setWeakNotification(row, col);
   }
 
@@ -215,17 +215,18 @@ public class TestTransaction implements TransactionBase {
   }
 
   @Override
-  public Map<String, Map<Column, String>> gets(Collection<String> rows, Set<Column> columns) {
+  public Map<String, Map<Column, String>> gets(Collection<? extends CharSequence> rows,
+      Set<Column> columns) {
     return tx.gets(rows, columns);
   }
 
   @Override
-  public String gets(String row, Column column) {
+  public String gets(CharSequence row, Column column) {
     return tx.gets(row, column);
   }
 
   @Override
-  public Map<Column, String> gets(String row, Set<Column> columns) {
+  public Map<Column, String> gets(CharSequence row, Set<Column> columns) {
     return tx.gets(row, columns);
   }