Repository: accumulo
Updated Branches:
  refs/heads/master aac52a82e -> 6b94344d4


ACCUMULO-2817 Added decode(byte[], int, int) to Lexicoder and Encoder 
implementations, but not to the interfaces themselves.

* Added AbstractEncoder and AbstractLexicoder to refactor common 'decode' 
functionality.
* Refactored existing implementations of Lexicoder to extend AbstractLexicoder, 
and Encoders to extend AbstractEncoder.

Signed-off-by: Josh Elser <els...@apache.org>


Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo
Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/6b94344d
Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/6b94344d
Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/6b94344d

Branch: refs/heads/master
Commit: 6b94344d43fb08896cafdf83f907f7a4237b4dc0
Parents: aac52a8
Author: matt dailey <matthew.dail...@gmail.com>
Authored: Tue Feb 17 18:58:50 2015 -0500
Committer: Josh Elser <els...@apache.org>
Committed: Wed Feb 25 21:54:16 2015 -0500

----------------------------------------------------------------------
 .../core/client/lexicoder/AbstractEncoder.java  | 60 +++++++++++++
 .../client/lexicoder/BigIntegerLexicoder.java   | 21 ++---
 .../core/client/lexicoder/BytesLexicoder.java   | 20 ++++-
 .../core/client/lexicoder/DateLexicoder.java    |  8 +-
 .../core/client/lexicoder/DoubleLexicoder.java  |  8 +-
 .../core/client/lexicoder/IntegerLexicoder.java |  8 +-
 .../core/client/lexicoder/ListLexicoder.java    | 14 +--
 .../core/client/lexicoder/LongLexicoder.java    |  4 +-
 .../core/client/lexicoder/PairLexicoder.java    | 11 +--
 .../core/client/lexicoder/ReverseLexicoder.java | 15 ++--
 .../core/client/lexicoder/StringLexicoder.java  |  8 +-
 .../core/client/lexicoder/TextLexicoder.java    |  9 +-
 .../client/lexicoder/UIntegerLexicoder.java     | 16 ++--
 .../core/client/lexicoder/ULongLexicoder.java   | 16 ++--
 .../core/client/lexicoder/UUIDLexicoder.java    | 13 +--
 .../lexicoder/impl/AbstractLexicoder.java       | 23 +++++
 .../core/client/lexicoder/impl/ByteUtils.java   | 13 ++-
 .../accumulo/core/iterators/LongCombiner.java   | 27 ++++--
 .../core/iterators/user/BigDecimalCombiner.java |  7 +-
 .../iterators/user/SummingArrayCombiner.java    | 14 +--
 .../lexicoder/BigIntegerLexicoderTest.java      | 12 ++-
 .../client/lexicoder/BytesLexicoderTest.java    | 28 ++++++
 .../client/lexicoder/DateLexicoderTest.java     | 30 +++++++
 .../client/lexicoder/DoubleLexicoderTest.java   | 14 ++-
 .../client/lexicoder/IntegerLexicoderTest.java  | 12 ++-
 .../core/client/lexicoder/LexicoderTest.java    | 31 +++++--
 .../client/lexicoder/ListLexicoderTest.java     | 33 ++++---
 .../client/lexicoder/LongLexicoderTest.java     | 13 ++-
 .../client/lexicoder/PairLexicoderTest.java     | 12 ++-
 .../client/lexicoder/ReverseLexicoderTest.java  | 15 +++-
 .../client/lexicoder/StringLexicoderTest.java   | 28 ++++++
 .../client/lexicoder/TextLexicoderTest.java     | 28 ++++++
 .../client/lexicoder/UIntegerLexicoderTest.java | 12 ++-
 .../client/lexicoder/ULongLexicoderTest.java    | 13 ++-
 .../client/lexicoder/UUIDLexicoderTest.java     |  9 +-
 .../lexicoder/impl/AbstractLexicoderTest.java   | 94 ++++++++++++++++++++
 .../client/lexicoder/impl/ByteUtilsTest.java    | 71 +++++++++++++++
 .../core/iterators/user/CombinerTest.java       |  4 +
 .../server/replication/StatusCombiner.java      | 24 ++++-
 39 files changed, 682 insertions(+), 116 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/AbstractEncoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/AbstractEncoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/AbstractEncoder.java
new file mode 100644
index 0000000..b266e53
--- /dev/null
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/AbstractEncoder.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.accumulo.core.client.lexicoder;
+
+import com.google.common.base.Preconditions;
+import org.apache.accumulo.core.iterators.ValueFormatException;
+
+/**
+ * AbstractEncoder is an {@link 
org.apache.accumulo.core.client.lexicoder.Encoder} that implements all of 
Encoder's
+ * methods validating the input, but has those methods defer logic to to a new 
method,
+ * {@link #decodeUnchecked(byte[], int, int)}.
+ * @since 1.7.0
+ */
+public abstract class AbstractEncoder<T> implements Encoder<T> {
+
+  /**
+   * Decodes a byte array without checking if the offset and len exceed the 
bounds of the actual array.
+   */
+  protected abstract T decodeUnchecked(byte[] b, int offset, int len) throws 
ValueFormatException;
+
+  /**
+   * Calls {@link #decodeUnchecked(byte[], int, int)} as {@code 
decodeUnchecked(b, 0, b.length);}.
+   */
+  @Override
+  public T decode(byte[] b) {
+    Preconditions.checkNotNull(b, "cannot decode null byte array");
+    return decodeUnchecked(b, 0, b.length);
+  }
+
+  /**
+   * Checks if the byte array is null, or if parameters exceed the bounds of 
the byte array,
+   * then calls {@link #decodeUnchecked(byte[], int, int)}.
+   *
+   * @throws java.lang.NullPointerException if {@code b} is null
+   * @throws java.lang.IllegalArgumentException if {@code offset + len} 
exceeds the length of {@code b}
+   */
+  public T decode(byte[] b, int offset, int len) {
+    Preconditions.checkNotNull(b, "cannot decode null byte array");
+    Preconditions.checkArgument(offset >= 0, "offset %s cannot be negative", 
offset);
+    Preconditions.checkArgument(len >= 0, "length %s cannot be negative", len);
+    Preconditions.checkArgument(offset + len < b.length, "offset + length %s 
exceeds byte array length %s",
+            (offset + len), b.length);
+
+    return decodeUnchecked(b, offset, len);
+  }
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java
index 838e3cd..577e33e 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoder.java
@@ -16,21 +16,22 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+import 
org.apache.accumulo.core.client.lexicoder.impl.FixedByteArrayOutputStream;
+import org.apache.accumulo.core.iterators.ValueFormatException;
+
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.math.BigInteger;
 
-import 
org.apache.accumulo.core.client.lexicoder.impl.FixedByteArrayOutputStream;
-import org.apache.accumulo.core.iterators.ValueFormatException;
-
 /**
  * A lexicoder to encode/decode a BigInteger to/from bytes that maintain its 
native Java sort order.
  *
  * @since 1.6.0
  */
-public class BigIntegerLexicoder implements Lexicoder<BigInteger> {
+public class BigIntegerLexicoder extends AbstractLexicoder<BigInteger> 
implements Lexicoder<BigInteger> {
 
   @Override
   public byte[] encode(BigInteger v) {
@@ -63,15 +64,15 @@ public class BigIntegerLexicoder implements 
Lexicoder<BigInteger> {
   }
 
   @Override
-  public BigInteger decode(byte[] b) throws ValueFormatException {
+  protected BigInteger decodeUnchecked(byte[] b, int offset, int origLen) 
throws ValueFormatException {
 
     try {
-      DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b));
-      int len = dis.readInt();
-      len = len ^ 0x80000000;
-      len = Math.abs(len);
+      DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b, 
offset, origLen));
+      int newLen = dis.readInt();
+      newLen = newLen ^ 0x80000000;
+      newLen = Math.abs(newLen);
 
-      byte[] bytes = new byte[len];
+      byte[] bytes = new byte[newLen];
       dis.readFully(bytes);
 
       bytes[0] = (byte) (0x80 ^ bytes[0]);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java
index e018e0c..8e0f5e2 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoder.java
@@ -16,13 +16,15 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
 /**
  * For each of the methods, this lexicoder just passes the input through 
untouched. It is meant to be combined with other lexicoders like the
  * {@link ReverseLexicoder}.
  *
  * @since 1.6.0
  */
-public class BytesLexicoder implements Lexicoder<byte[]> {
+public class BytesLexicoder extends AbstractLexicoder<byte[]> implements 
Lexicoder<byte[]> {
 
   @Override
   public byte[] encode(byte[] data) {
@@ -31,7 +33,23 @@ public class BytesLexicoder implements Lexicoder<byte[]> {
 
   @Override
   public byte[] decode(byte[] data) {
+    // overrides AbstractLexicoder since this simply returns the array
     return data;
   }
 
+  /**
+   * If offset == 0 and len == data.length, returns data.  Otherwise, returns 
a new
+   * byte array with contents starting at data[offset] with length len.
+   */
+  @Override
+  protected byte[] decodeUnchecked(byte[] data, int offset, int len) {
+    if (offset == 0 && len == data.length) {
+      return data;
+    }
+
+    byte[] copy = new byte[len];
+    System.arraycopy(data, offset, copy, 0, len);
+    return copy;
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java
index 8533bfe..2d17d37 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DateLexicoder.java
@@ -16,6 +16,8 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
 import java.util.Date;
 
 /**
@@ -23,7 +25,7 @@ import java.util.Date;
  *
  * @since 1.6.0
  */
-public class DateLexicoder implements Lexicoder<Date> {
+public class DateLexicoder extends AbstractLexicoder<Date> implements 
Lexicoder<Date> {
 
   private LongLexicoder longEncoder = new LongLexicoder();
 
@@ -33,8 +35,8 @@ public class DateLexicoder implements Lexicoder<Date> {
   }
 
   @Override
-  public Date decode(byte[] data) {
-    return new Date(longEncoder.decode(data));
+  protected Date decodeUnchecked(byte[] data, int offset, int len) {
+    return new Date(longEncoder.decodeUnchecked(data, offset, len));
   }
 
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java
index 6310645..14413c0 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoder.java
@@ -16,12 +16,14 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
 /**
  * A lexicoder for preserving the native Java sort order of Double values.
  *
  * @since 1.6.0
  */
-public class DoubleLexicoder implements Lexicoder<Double> {
+public class DoubleLexicoder extends AbstractLexicoder<Double> implements 
Lexicoder<Double> {
 
   private ULongLexicoder longEncoder = new ULongLexicoder();
 
@@ -37,8 +39,8 @@ public class DoubleLexicoder implements Lexicoder<Double> {
   }
 
   @Override
-  public Double decode(byte[] data) {
-    long l = longEncoder.decode(data);
+  protected Double decodeUnchecked(byte[] data, int offset, int len) {
+    long l = longEncoder.decodeUnchecked(data, offset, len);
     if (l < 0)
       l = l ^ 0x8000000000000000l;
     else

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java
index 12b515a..f96b41d 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoder.java
@@ -16,13 +16,15 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
 /**
  * A lexicoder for signed integers. The encoding sorts Integer.MIN_VALUE first 
and Integer.MAX_VALUE last. The encoding sorts -2 before -1. It corresponds to
  * the sort order of Integer.
  *
  * @since 1.6.0
  */
-public class IntegerLexicoder implements Lexicoder<Integer> {
+public class IntegerLexicoder extends AbstractLexicoder<Integer> implements 
Lexicoder<Integer> {
 
   private UIntegerLexicoder uil = new UIntegerLexicoder();
 
@@ -32,8 +34,8 @@ public class IntegerLexicoder implements Lexicoder<Integer> {
   }
 
   @Override
-  public Integer decode(byte[] data) {
-    return uil.decode(data) ^ 0x80000000;
+  protected Integer decodeUnchecked(byte[] data, int offset, int len) {
+    return uil.decodeUnchecked(data, offset, len) ^ 0x80000000;
   }
 
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java
index 5ecee88..a92f4c6 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ListLexicoder.java
@@ -16,20 +16,22 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
+import java.util.ArrayList;
+import java.util.List;
+
 import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.concat;
 import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.escape;
 import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.split;
 import static 
org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.unescape;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * A lexicoder to encode/decode a Java List to/from a byte array where the 
concatenation of each encoded element sorts lexicographically.
  *
  * @since 1.6.0
  */
-public class ListLexicoder<LT> implements Lexicoder<List<LT>> {
+public class ListLexicoder<LT> extends AbstractLexicoder<List<LT>> implements 
Lexicoder<List<LT>> {
 
   private Lexicoder<LT> lexicoder;
 
@@ -53,9 +55,9 @@ public class ListLexicoder<LT> implements Lexicoder<List<LT>> 
{
   }
 
   @Override
-  public List<LT> decode(byte[] b) {
+  protected List<LT> decodeUnchecked(byte[] b, int offset, int len) {
 
-    byte[][] escapedElements = split(b);
+    byte[][] escapedElements = split(b, offset, len);
     ArrayList<LT> ret = new ArrayList<LT>(escapedElements.length);
 
     for (byte[] escapedElement : escapedElements) {

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java
index f70a83c..ec850a3 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/LongLexicoder.java
@@ -29,7 +29,7 @@ public class LongLexicoder extends ULongLexicoder {
   }
 
   @Override
-  public Long decode(byte[] data) {
-    return super.decode(data) ^ 0x8000000000000000l;
+  protected Long decodeUnchecked(byte[] data, int offset, int len) {
+    return super.decodeUnchecked(data, offset, len) ^ 0x8000000000000000l;
   }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java
index 22af289..dff946f 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/PairLexicoder.java
@@ -16,13 +16,14 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+import org.apache.accumulo.core.util.ComparablePair;
+
 import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.concat;
 import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.escape;
 import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.split;
 import static 
org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.unescape;
 
-import org.apache.accumulo.core.util.ComparablePair;
-
 /**
  * This class is a lexicoder that sorts a ComparablePair. Each item in the 
pair is encoded with the given lexicoder and concatenated together. This makes 
it
  * easy to construct a sortable key based on two components. There are many 
examples of this- but a key/value relationship is a great one.
@@ -48,7 +49,7 @@ import org.apache.accumulo.core.util.ComparablePair;
  * @since 1.6.0
  */
 
-public class PairLexicoder<A extends Comparable<A>,B extends Comparable<B>> 
implements Lexicoder<ComparablePair<A,B>> {
+public class PairLexicoder<A extends Comparable<A>,B extends Comparable<B>> 
extends AbstractLexicoder<ComparablePair<A,B>> implements 
Lexicoder<ComparablePair<A,B>> {
 
   private Lexicoder<A> firstLexicoder;
   private Lexicoder<B> secondLexicoder;
@@ -64,9 +65,9 @@ public class PairLexicoder<A extends Comparable<A>,B extends 
Comparable<B>> impl
   }
 
   @Override
-  public ComparablePair<A,B> decode(byte[] data) {
+  protected ComparablePair<A,B> decodeUnchecked(byte[] data, int offset, int 
len) {
 
-    byte[][] fields = split(data);
+    byte[][] fields = split(data, offset, len);
     if (fields.length != 2) {
       throw new RuntimeException("Data does not have 2 fields, it has " + 
fields.length);
     }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java
index 1a6999b..3a422d5 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoder.java
@@ -16,6 +16,8 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
 import static org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.escape;
 import static 
org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.unescape;
 
@@ -27,7 +29,7 @@ import static 
org.apache.accumulo.core.client.lexicoder.impl.ByteUtils.unescape;
  * @since 1.6.0
  */
 
-public class ReverseLexicoder<T> implements Lexicoder<T> {
+public class ReverseLexicoder<T> extends AbstractLexicoder<T> implements 
Lexicoder<T> {
 
   private Lexicoder<T> lexicoder;
 
@@ -53,11 +55,14 @@ public class ReverseLexicoder<T> implements Lexicoder<T> {
   }
 
   @Override
-  public T decode(byte[] data) {
-    byte ret[] = new byte[data.length - 1];
+  protected T decodeUnchecked(byte[] data, int offset, int len) {
+    byte ret[] = new byte[len - 1];
 
-    for (int i = 0; i < ret.length; i++)
-      ret[i] = (byte) (0xff - (0xff & data[i]));
+    int dataIndex;
+    for (int i = 0; i < ret.length; i++) {
+      dataIndex = offset + i;
+      ret[i] = (byte) (0xff - (0xff & data[dataIndex]));
+    }
 
     return lexicoder.decode(unescape(ret));
   }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java
index 9d5e07e..f7b1877 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/StringLexicoder.java
@@ -16,6 +16,8 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 /**
@@ -25,7 +27,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
  * @since 1.6.0
  */
 
-public class StringLexicoder implements Lexicoder<String> {
+public class StringLexicoder extends AbstractLexicoder<String> implements 
Lexicoder<String> {
 
   @Override
   public byte[] encode(String data) {
@@ -33,8 +35,8 @@ public class StringLexicoder implements Lexicoder<String> {
   }
 
   @Override
-  public String decode(byte[] data) {
-    return new String(data, UTF_8);
+  protected String decodeUnchecked(byte[] data, int offset, int len) {
+    return new String(data, offset, len, UTF_8);
   }
 
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java
index 08837a5..bb29857 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/TextLexicoder.java
@@ -16,6 +16,7 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
 import org.apache.accumulo.core.util.TextUtil;
 import org.apache.hadoop.io.Text;
 
@@ -26,7 +27,7 @@ import org.apache.hadoop.io.Text;
  * @since 1.6.0
  */
 
-public class TextLexicoder implements Lexicoder<Text> {
+public class TextLexicoder extends AbstractLexicoder<Text> implements 
Lexicoder<Text> {
 
   @Override
   public byte[] encode(Text data) {
@@ -34,8 +35,10 @@ public class TextLexicoder implements Lexicoder<Text> {
   }
 
   @Override
-  public Text decode(byte[] data) {
-    return new Text(data);
+  protected Text decodeUnchecked(byte[] data, int offset, int len) {
+    Text text = new Text();
+    text.set(data, offset, len);
+    return text;
   }
 
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java
index f8842a9..e99c3b1 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoder.java
@@ -16,13 +16,15 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
 /**
  * A lexicoder for an unsigned integer. It sorts 0 before -1 and does not 
preserve the native sort order of a Java integer because Java does not contain 
an
  * unsigned integer. If Java had an unsigned integer type, this would 
correspond to its sort order.
  *
  * @since 1.6.0
  */
-public class UIntegerLexicoder implements Lexicoder<Integer> {
+public class UIntegerLexicoder extends AbstractLexicoder<Integer> implements 
Lexicoder<Integer> {
 
   @Override
   public byte[] encode(Integer i) {
@@ -52,22 +54,22 @@ public class UIntegerLexicoder implements 
Lexicoder<Integer> {
   }
 
   @Override
-  public Integer decode(byte[] data) {
+  protected Integer decodeUnchecked(byte[] data, int offset, int len) {
 
-    if (data[0] < 0 || data[0] > 8)
-      throw new IllegalArgumentException("Unexpected length " + (0xff & 
data[0]));
+    if (data[offset] < 0 || data[offset] > 8)
+      throw new IllegalArgumentException("Unexpected length " + (0xff & 
data[offset]));
 
     int i = 0;
     int shift = 0;
 
-    for (int idx = data.length - 1; idx >= 1; idx--) {
+    for (int idx = (offset + len) - 1; idx >= offset + 1; idx--) {
       i += (data[idx] & 0xffl) << shift;
       shift += 8;
     }
 
     // fill in 0xff prefix
-    if (data[0] > 4)
-      i |= -1 << ((8 - data[0]) << 3);
+    if (data[offset] > 4)
+      i |= -1 << ((8 - data[offset]) << 3);
 
     return i;
   }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java
index a3dcab5..a69ed34 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoder.java
@@ -16,13 +16,15 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+
 /**
  * Unsigned long lexicoder. The lexicographic encoding sorts first 0l and -1l 
last. This encoding does not correspond to the sort of Long because it does not
  * consider the sign bit. If Java had an unsigned long type, this encoder 
would correspond to its sort order.
  *
  * @since 1.6.0
  */
-public class ULongLexicoder implements Lexicoder<Long> {
+public class ULongLexicoder extends AbstractLexicoder<Long> implements 
Lexicoder<Long> {
 
   @Override
   public byte[] encode(Long l) {
@@ -52,22 +54,22 @@ public class ULongLexicoder implements Lexicoder<Long> {
   }
 
   @Override
-  public Long decode(byte[] data) {
+  protected Long decodeUnchecked(byte[] data, int offset, int len) {
 
     long l = 0;
     int shift = 0;
 
-    if (data[0] < 0 || data[0] > 16)
-      throw new IllegalArgumentException("Unexpected length " + (0xff & 
data[0]));
+    if (data[offset] < 0 || data[offset] > 16)
+      throw new IllegalArgumentException("Unexpected length " + (0xff & 
data[offset]));
 
-    for (int i = data.length - 1; i >= 1; i--) {
+    for (int i = (offset + len) - 1; i >= offset + 1; i--) {
       l += (data[i] & 0xffl) << shift;
       shift += 8;
     }
 
     // fill in 0xff prefix
-    if (data[0] > 8)
-      l |= -1l << ((16 - data[0]) << 3);
+    if (data[offset] > 8)
+      l |= -1l << ((16 - data[offset]) << 3);
 
     return l;
   }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java
index 43fa1a4..98ee467 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoder.java
@@ -16,21 +16,22 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
+import 
org.apache.accumulo.core.client.lexicoder.impl.FixedByteArrayOutputStream;
+import org.apache.accumulo.core.iterators.ValueFormatException;
+
 import java.io.ByteArrayInputStream;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.IOException;
 import java.util.UUID;
 
-import 
org.apache.accumulo.core.client.lexicoder.impl.FixedByteArrayOutputStream;
-import org.apache.accumulo.core.iterators.ValueFormatException;
-
 /**
  * A lexicoder for a UUID that maintains its lexicographic sorting order.
  *
  * @since 1.6.0
  */
-public class UUIDLexicoder implements Lexicoder<UUID> {
+public class UUIDLexicoder extends AbstractLexicoder<UUID> implements 
Lexicoder<UUID> {
 
   /**
    * @see <a href="http://www.ietf.org/rfc/rfc4122.txt";> RFC 4122: A 
Universally Unique IDentifier (UUID) URN Namespace, "Rules for Lexical 
Equivalence" in
@@ -54,9 +55,9 @@ public class UUIDLexicoder implements Lexicoder<UUID> {
   }
 
   @Override
-  public UUID decode(byte[] b) throws ValueFormatException {
+  protected UUID decodeUnchecked(byte[] b, int offset, int len) throws 
ValueFormatException {
     try {
-      DataInputStream in = new DataInputStream(new ByteArrayInputStream(b));
+      DataInputStream in = new DataInputStream(new ByteArrayInputStream(b, 
offset, len));
       return new UUID(in.readLong() ^ 0x8000000000000000l, in.readLong() ^ 
0x8000000000000000l);
     } catch (IOException e) {
       throw new RuntimeException(e);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoder.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoder.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoder.java
new file mode 100644
index 0000000..e568f25
--- /dev/null
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoder.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.accumulo.core.client.lexicoder.impl;
+
+import org.apache.accumulo.core.client.lexicoder.AbstractEncoder;
+import org.apache.accumulo.core.client.lexicoder.Lexicoder;
+
+public abstract class AbstractLexicoder<T> extends AbstractEncoder<T> 
implements Lexicoder<T> {
+}

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java
 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java
index 4973de8..b168807 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtils.java
@@ -90,19 +90,26 @@ public class ByteUtils {
    * Splits a byte array by 0x00
    */
   public static byte[][] split(byte[] data) {
+    return split(data, 0, data.length);
+  }
+
+  /**
+   * Splits a byte array by 0x00
+   */
+  public static byte[][] split(byte[] data, int dataOffset, int len) {
     ArrayList<Integer> offsets = new ArrayList<Integer>();
 
-    for (int i = 0; i < data.length; i++) {
+    for (int i = dataOffset; i < (dataOffset + len); i++) {
       if (data[i] == 0x00) {
         offsets.add(i);
       }
     }
 
-    offsets.add(data.length);
+    offsets.add(dataOffset + len);
 
     byte[][] ret = new byte[offsets.size()][];
 
-    int index = 0;
+    int index = dataOffset;
     for (int i = 0; i < offsets.size(); i++) {
       ret[i] = new byte[offsets.get(i) - index];
       System.arraycopy(data, index, ret[i], 0, ret[i].length);

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java 
b/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java
index ad98968..2a225fd 100644
--- a/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java
+++ b/core/src/main/java/org/apache/accumulo/core/iterators/LongCombiner.java
@@ -26,6 +26,7 @@ import java.io.IOException;
 import java.util.Map;
 
 import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Value;
 import org.apache.hadoop.io.WritableUtils;
@@ -117,7 +118,7 @@ public abstract class LongCombiner extends 
TypedValueCombiner<Long> {
   /**
    * An Encoder that uses a variable-length encoding for Longs. It uses 
WritableUtils.writeVLong and WritableUtils.readVLong for encoding and decoding.
    */
-  public static class VarLenEncoder implements Encoder<Long> {
+  public static class VarLenEncoder extends AbstractLexicoder<Long> implements 
Encoder<Long> {
     @Override
     public byte[] encode(Long v) {
       ByteArrayOutputStream baos = new ByteArrayOutputStream();
@@ -133,8 +134,8 @@ public abstract class LongCombiner extends 
TypedValueCombiner<Long> {
     }
 
     @Override
-    public Long decode(byte[] b) {
-      DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b));
+    protected Long decodeUnchecked(byte[] b, int offset, int len) {
+      DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b, 
offset, len));
       try {
         return WritableUtils.readVLong(dis);
       } catch (IOException e) {
@@ -146,7 +147,7 @@ public abstract class LongCombiner extends 
TypedValueCombiner<Long> {
   /**
    * An Encoder that uses an 8-byte encoding for Longs.
    */
-  public static class FixedLenEncoder implements Encoder<Long> {
+  public static class FixedLenEncoder extends AbstractLexicoder<Long> 
implements Encoder<Long> {
     @Override
     public byte[] encode(Long l) {
       byte[] b = new byte[8];
@@ -162,31 +163,39 @@ public abstract class LongCombiner extends 
TypedValueCombiner<Long> {
     }
 
     @Override
-    public Long decode(byte[] b) {
-      return decode(b, 0);
+    protected Long decodeUnchecked(byte[] b, int offset, int len) {
+      return decodeStatic(b, offset, len);
     }
 
+    // refactor?  it's public, so cannot remove
     public static long decode(byte[] b, int offset) {
       if (b.length < offset + 8)
         throw new ValueFormatException("trying to convert to long, but byte 
array isn't long enough, wanted " + (offset + 8) + " found " + b.length);
       return (((long) b[offset + 0] << 56) + ((long) (b[offset + 1] & 255) << 
48) + ((long) (b[offset + 2] & 255) << 40) + ((long) (b[offset + 3] & 255) << 
32)
           + ((long) (b[offset + 4] & 255) << 24) + ((b[offset + 5] & 255) << 
16) + ((b[offset + 6] & 255) << 8) + ((b[offset + 7] & 255) << 0));
     }
+
+    public static long decodeStatic(byte[] b, int offset, int len) {
+      if (b.length < offset + 8 || len < 8)
+        throw new ValueFormatException("trying to convert to long, but byte 
array isn't long enough, wanted " + (offset + 8) + " found " + len);
+      return (((long) b[offset + 0] << 56) + ((long) (b[offset + 1] & 255) << 
48) + ((long) (b[offset + 2] & 255) << 40) + ((long) (b[offset + 3] & 255) << 
32)
+              + ((long) (b[offset + 4] & 255) << 24) + ((b[offset + 5] & 255) 
<< 16) + ((b[offset + 6] & 255) << 8) + ((b[offset + 7] & 255) << 0));
+    }
   }
 
   /**
    * An Encoder that uses a String representation of Longs. It uses 
Long.toString and Long.parseLong for encoding and decoding.
    */
-  public static class StringEncoder implements Encoder<Long> {
+  public static class StringEncoder extends AbstractLexicoder<Long> implements 
Encoder<Long> {
     @Override
     public byte[] encode(Long v) {
       return Long.toString(v).getBytes(UTF_8);
     }
 
     @Override
-    public Long decode(byte[] b) {
+    protected Long decodeUnchecked(byte[] b, int offset, int len) {
       try {
-        return Long.parseLong(new String(b, UTF_8));
+        return Long.parseLong(new String(b, offset, len, UTF_8));
       } catch (NumberFormatException nfe) {
         throw new ValueFormatException(nfe);
       }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java
 
b/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java
index 86c9e73..3a6dbcb 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/iterators/user/BigDecimalCombiner.java
@@ -23,6 +23,7 @@ import java.math.BigDecimal;
 import java.util.Iterator;
 import java.util.Map;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.iterators.IteratorEnvironment;
@@ -100,16 +101,16 @@ public abstract class BigDecimalCombiner extends 
TypedValueCombiner<BigDecimal>
    * Provides the ability to encode scientific notation.
    *
    */
-  public static class BigDecimalEncoder implements 
org.apache.accumulo.core.iterators.TypedValueCombiner.Encoder<BigDecimal> {
+  public static class BigDecimalEncoder extends AbstractLexicoder<BigDecimal> 
implements 
org.apache.accumulo.core.iterators.TypedValueCombiner.Encoder<BigDecimal> {
     @Override
     public byte[] encode(BigDecimal v) {
       return v.toString().getBytes(UTF_8);
     }
 
     @Override
-    public BigDecimal decode(byte[] b) throws ValueFormatException {
+    protected BigDecimal decodeUnchecked(byte[] b, int offset, int len) throws 
ValueFormatException {
       try {
-        return new BigDecimal(new String(b, UTF_8));
+        return new BigDecimal(new String(b, offset, len, UTF_8));
       } catch (NumberFormatException nfe) {
         throw new ValueFormatException(nfe);
       }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java
----------------------------------------------------------------------
diff --git 
a/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java
 
b/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java
index 2217d13..04c0af1 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/iterators/user/SummingArrayCombiner.java
@@ -30,6 +30,8 @@ import java.util.List;
 import java.util.Map;
 
 import org.apache.accumulo.core.client.IteratorSetting;
+import org.apache.accumulo.core.client.lexicoder.AbstractEncoder;
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoder;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.iterators.IteratorEnvironment;
@@ -140,7 +142,7 @@ public class SummingArrayCombiner extends 
TypedValueCombiner<List<Long>> {
     return true;
   }
 
-  public abstract static class DOSArrayEncoder<V> implements Encoder<List<V>> {
+  public abstract static class DOSArrayEncoder<V> extends 
AbstractLexicoder<List<V>> implements Encoder<List<V>> {
     public abstract void write(DataOutputStream dos, V v) throws IOException;
 
     public abstract V read(DataInputStream dis) throws IOException;
@@ -161,8 +163,8 @@ public class SummingArrayCombiner extends 
TypedValueCombiner<List<Long>> {
     }
 
     @Override
-    public List<V> decode(byte[] b) {
-      DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b));
+    protected List<V> decodeUnchecked(byte[] b, int offset, int origLen) {
+      DataInputStream dis = new DataInputStream(new ByteArrayInputStream(b, 
offset, origLen));
       try {
         int len = WritableUtils.readVInt(dis);
         List<V> vl = new ArrayList<V>(len);
@@ -200,7 +202,7 @@ public class SummingArrayCombiner extends 
TypedValueCombiner<List<Long>> {
     }
   }
 
-  public static class StringArrayEncoder implements Encoder<List<Long>> {
+  public static class StringArrayEncoder extends AbstractEncoder<List<Long>> 
implements Encoder<List<Long>> {
     @Override
     public byte[] encode(List<Long> la) {
       if (la.size() == 0)
@@ -214,8 +216,8 @@ public class SummingArrayCombiner extends 
TypedValueCombiner<List<Long>> {
     }
 
     @Override
-    public List<Long> decode(byte[] b) {
-      String[] longstrs = new String(b, UTF_8).split(",");
+    protected List<Long> decodeUnchecked(byte[] b, int offset, int len) {
+      String[] longstrs = new String(b, offset, len, UTF_8).split(",");
       List<Long> la = new ArrayList<Long>(longstrs.length);
       for (String s : longstrs) {
         if (s.length() == 0)

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java
index 9d453e3..9165fe5 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BigIntegerLexicoderTest.java
@@ -16,13 +16,15 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
 import java.math.BigInteger;
 import java.util.Arrays;
 
 /**
  *
  */
-public class BigIntegerLexicoderTest extends LexicoderTest {
+public class BigIntegerLexicoderTest extends AbstractLexicoderTest {
   public void testSortOrder() {
     assertSortOrder(new BigIntegerLexicoder(), Arrays.asList(new 
BigInteger("-1"), new BigInteger("0"), new BigInteger("1"), new 
BigInteger("-257"),
         new BigInteger("-256"), new BigInteger("-255"), new BigInteger("255"), 
new BigInteger("256"), new BigInteger("257"), new BigInteger("65534"),
@@ -33,4 +35,12 @@ public class BigIntegerLexicoderTest extends LexicoderTest {
         new BigInteger("128"), new BigInteger("129"), new BigInteger("-126"), 
new BigInteger("-127"), new BigInteger("-128"), new BigInteger("-129")));
 
   }
+
+  public void testDecode() {
+    assertDecodes(new BigIntegerLexicoder(), new BigInteger("-2147483649"));
+    assertDecodes(new BigIntegerLexicoder(), new BigInteger("-1"));
+    assertDecodes(new BigIntegerLexicoder(), BigInteger.ZERO);
+    assertDecodes(new BigIntegerLexicoder(), BigInteger.ONE);
+    assertDecodes(new BigIntegerLexicoder(), new BigInteger("2147483647"));
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoderTest.java
new file mode 100644
index 0000000..3f5b991
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/BytesLexicoderTest.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.accumulo.core.client.lexicoder;
+
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
+public class BytesLexicoderTest extends AbstractLexicoderTest {
+
+  public void testDecodes() {
+    BytesLexicoder lexicoder = new BytesLexicoder();
+    assertDecodesB(lexicoder, new byte[0]);
+    assertDecodesB(lexicoder, "accumulo".getBytes());
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DateLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DateLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DateLexicoderTest.java
new file mode 100644
index 0000000..98d3ed1
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DateLexicoderTest.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.accumulo.core.client.lexicoder;
+
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
+import java.util.Date;
+
+public class DateLexicoderTest extends AbstractLexicoderTest {
+
+  public void testDecode() throws Exception {
+    assertDecodes(new DateLexicoder(), new Date());
+    assertDecodes(new DateLexicoder(), new Date(0));
+    assertDecodes(new DateLexicoder(), new Date(Long.MAX_VALUE));
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java
index fc37f04..1b082b4 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/DoubleLexicoderTest.java
@@ -16,12 +16,14 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
 import java.util.Arrays;
 
 /**
  *
  */
-public class DoubleLexicoderTest extends LexicoderTest {
+public class DoubleLexicoderTest extends AbstractLexicoderTest {
   public void testSortOrder() {
     assertSortOrder(new DoubleLexicoder(), Arrays.asList(Double.MIN_VALUE, 
Double.MAX_VALUE, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, 0.0, 0.01,
         0.001, 1.0, -1.0, -1.1, -1.01, Math.nextUp(Double.NEGATIVE_INFINITY), 
Math.nextAfter(0.0, Double.NEGATIVE_INFINITY),
@@ -29,4 +31,14 @@ public class DoubleLexicoderTest extends LexicoderTest {
         Math.pow(10.0, -30.0)));
 
   }
+
+  public void testDecode() {
+    assertDecodes(new DoubleLexicoder(), Double.MIN_VALUE);
+    assertDecodes(new DoubleLexicoder(), -1.0);
+    assertDecodes(new DoubleLexicoder(), -Math.pow(10.0, -30.0));
+    assertDecodes(new DoubleLexicoder(), 0.0);
+    assertDecodes(new DoubleLexicoder(), Math.pow(10.0, -30.0));
+    assertDecodes(new DoubleLexicoder(), 1.0);
+    assertDecodes(new DoubleLexicoder(), Double.MAX_VALUE);
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java
index 0af4792..4ca9235 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/IntegerLexicoderTest.java
@@ -16,11 +16,21 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
 import java.util.Arrays;
 
-public class IntegerLexicoderTest extends LexicoderTest {
+public class IntegerLexicoderTest extends AbstractLexicoderTest {
   public void testSortOrder() {
     assertSortOrder(new IntegerLexicoder(),
         Arrays.asList(Integer.MIN_VALUE, 0xff123456, 0xffff3456, 0xffffff56, 
-1, 0, 1, 0x12, 0x1234, 0x123456, 0x1234678, Integer.MAX_VALUE));
   }
+
+  public void testDecode() {
+    assertDecodes(new IntegerLexicoder(), Integer.MIN_VALUE);
+    assertDecodes(new IntegerLexicoder(), -1);
+    assertDecodes(new IntegerLexicoder(), 0);
+    assertDecodes(new IntegerLexicoder(), 1);
+    assertDecodes(new IntegerLexicoder(), Integer.MAX_VALUE);
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java
index 4b798b6..6d06f97 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LexicoderTest.java
@@ -16,19 +16,18 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import junit.framework.TestCase;
+import org.apache.accumulo.core.util.TextUtil;
+import org.apache.hadoop.io.Text;
+
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
-import junit.framework.TestCase;
-
-import org.apache.accumulo.core.util.TextUtil;
-import org.apache.hadoop.io.Text;
-
 public abstract class LexicoderTest extends TestCase {
 
-  void assertEqualsB(byte[] ba1, byte[] ba2) {
+  protected void assertEqualsB(byte[] ba1, byte[] ba2) {
     assertEquals(new Text(ba2), new Text(ba1));
   }
 
@@ -61,4 +60,24 @@ public abstract class LexicoderTest extends TestCase {
     assertSortOrder(lexicoder, null, data);
   }
 
+  public static final byte[] START_PAD = "start".getBytes();
+  public static final byte[] END_PAD = "end".getBytes();
+
+  /** Asserts a value can be encoded and decoded back to original value */
+  public static <T> void assertDecodes(Lexicoder<T> lexicoder, T expected) {
+    byte[] encoded = lexicoder.encode(expected);
+
+    // decode full array
+    T result = lexicoder.decode(encoded);
+    assertEquals(expected, result);
+  }
+
+  public void assertDecodesB(Lexicoder<byte[]> lexicoder, byte[] expected) {
+    byte[] encoded = lexicoder.encode(expected);
+
+    // decode full array
+    byte[] result = lexicoder.decode(encoded);
+    assertEqualsB(expected, result);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java
index 60a9f79..41084e6 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ListLexicoderTest.java
@@ -16,35 +16,40 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+import org.apache.accumulo.core.util.TextUtil;
+import org.apache.hadoop.io.Text;
+
 import java.util.ArrayList;
 import java.util.List;
 import java.util.TreeSet;
 
-import org.apache.accumulo.core.util.TextUtil;
-import org.apache.hadoop.io.Text;
+public class ListLexicoderTest extends AbstractLexicoderTest {
+
+  private List<Long> data1 = new ArrayList<Long>();
+  private List<Long> data2 = new ArrayList<Long>();
+  private List<Long> data3 = new ArrayList<Long>();
+  private List<Long> data4 = new ArrayList<Long>();
+  private List<Long> data5 = new ArrayList<Long>();
+
+  public void setUp() {
 
-public class ListLexicoderTest extends LexicoderTest {
-  public void testSortOrder() {
-    List<Long> data1 = new ArrayList<Long>();
     data1.add(1l);
     data1.add(2l);
 
-    List<Long> data2 = new ArrayList<Long>();
     data2.add(1l);
 
-    List<Long> data3 = new ArrayList<Long>();
     data3.add(1l);
     data3.add(3l);
 
-    List<Long> data4 = new ArrayList<Long>();
     data4.add(1l);
     data4.add(2l);
     data4.add(3l);
 
-    List<Long> data5 = new ArrayList<Long>();
     data5.add(2l);
     data5.add(1l);
-
+  }
+  public void testSortOrder() {
     List<List<Long>> data = new ArrayList<List<Long>>();
 
     // add list in expected sort order
@@ -71,4 +76,12 @@ public class ListLexicoderTest extends LexicoderTest {
     assertEquals(data, unenc);
 
   }
+
+  public void testDecodes() {
+    assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data1);
+    assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data2);
+    assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data3);
+    assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data4);
+    assertDecodes(new ListLexicoder<Long>(new LongLexicoder()), data5);
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java
index bf9a3a7..c1e2d41 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/LongLexicoderTest.java
@@ -16,13 +16,24 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
 import java.util.Arrays;
 
-public class LongLexicoderTest extends LexicoderTest {
+public class LongLexicoderTest extends AbstractLexicoderTest {
   public void testSortOrder() {
 
     assertSortOrder(new LongLexicoder(), Arrays.asList(Long.MIN_VALUE, 
0xff1234567890abcdl, 0xffff1234567890abl, 0xffffff567890abcdl, 
0xffffffff7890abcdl,
         0xffffffffff90abcdl, 0xffffffffffffabcdl, 0xffffffffffffffcdl, -1l, 
0l, 0x01l, 0x1234l, 0x123456l, 0x12345678l, 0x1234567890l, 0x1234567890abl,
         0x1234567890abcdl, 0x1234567890abcdefl, Long.MAX_VALUE));
   }
+
+  public void testDecodes() {
+    assertDecodes(new LongLexicoder(), Long.MIN_VALUE);
+    assertDecodes(new LongLexicoder(), -1l);
+    assertDecodes(new LongLexicoder(), 0l);
+    assertDecodes(new LongLexicoder(), 1l);
+    assertDecodes(new LongLexicoder(), 2l);
+    assertDecodes(new LongLexicoder(), Long.MAX_VALUE);
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java
index 434a603..0979801 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/PairLexicoderTest.java
@@ -16,14 +16,15 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
-import java.util.Arrays;
-
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
 import org.apache.accumulo.core.util.ComparablePair;
 
+import java.util.Arrays;
+
 /**
  *
  */
-public class PairLexicoderTest extends LexicoderTest {
+public class PairLexicoderTest extends AbstractLexicoderTest {
   public void testSortOrder() {
     PairLexicoder<String,String> plexc = new PairLexicoder<String,String>(new 
StringLexicoder(), new StringLexicoder());
 
@@ -36,4 +37,9 @@ public class PairLexicoderTest extends LexicoderTest {
     assertSortOrder(plexc2, Arrays.asList(new 
ComparablePair<Long,String>(0x100l, "a"), new 
ComparablePair<Long,String>(0x100l, "ab"),
         new ComparablePair<Long,String>(0xf0l, "a"), new 
ComparablePair<Long,String>(0xf0l, "ab")));
   }
+
+  public void testDecodes() {
+    PairLexicoder<String,String> plexc = new PairLexicoder<String,String>(new 
StringLexicoder(), new StringLexicoder());
+    assertDecodes(plexc, new ComparablePair<String,String>("a", "b"));
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java
index bde8a3f..a49409f 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ReverseLexicoderTest.java
@@ -16,6 +16,9 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+import org.junit.Test;
+
 import java.io.UnsupportedEncodingException;
 import java.util.Arrays;
 import java.util.Calendar;
@@ -23,9 +26,7 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
 
-import org.junit.Test;
-
-public class ReverseLexicoderTest extends LexicoderTest {
+public class ReverseLexicoderTest extends AbstractLexicoderTest {
   public void testSortOrder() {
     Comparator<Long> comp = Collections.reverseOrder();
     assertSortOrder(new ReverseLexicoder<Long>(new LongLexicoder()), comp, 
Arrays.asList(Long.MIN_VALUE, 0xff1234567890abcdl, 0xffff1234567890abl,
@@ -62,4 +63,12 @@ public class ReverseLexicoderTest extends LexicoderTest {
     System.out.println(date);
 
   }
+
+  public void testDecodes() {
+    assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), 
Long.MIN_VALUE);
+    assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), -1l);
+    assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), 0l);
+    assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), 1l);
+    assertDecodes(new ReverseLexicoder<Long>(new LongLexicoder()), 
Long.MAX_VALUE);
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/StringLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/StringLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/StringLexicoderTest.java
new file mode 100644
index 0000000..686ee46
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/StringLexicoderTest.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.accumulo.core.client.lexicoder;
+
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
+public class StringLexicoderTest extends AbstractLexicoderTest {
+
+  public void testDecode() throws Exception {
+    assertDecodes(new StringLexicoder(), "");
+    assertDecodes(new StringLexicoder(), "0");
+    assertDecodes(new StringLexicoder(), "accumulo");
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/TextLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/TextLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/TextLexicoderTest.java
new file mode 100644
index 0000000..74558de
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/TextLexicoderTest.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.accumulo.core.client.lexicoder;
+
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+import org.apache.hadoop.io.Text;
+
+public class TextLexicoderTest extends AbstractLexicoderTest {
+
+  public void testDecode() throws Exception {
+    assertDecodes(new TextLexicoder(), new Text(""));
+    assertDecodes(new TextLexicoder(), new Text("accumulo"));
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java
index bd59237..8c33d98 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UIntegerLexicoderTest.java
@@ -16,7 +16,9 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
-public class UIntegerLexicoderTest extends LexicoderTest {
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
+public class UIntegerLexicoderTest extends AbstractLexicoderTest {
   public void testEncoding() {
     UIntegerLexicoder uil = new UIntegerLexicoder();
 
@@ -30,4 +32,12 @@ public class UIntegerLexicoderTest extends LexicoderTest {
     assertEqualsB(uil.encode(0xffffff04), new byte[] {0x07, 0x04});
     assertEqualsB(uil.encode(-1), new byte[] {0x08});
   }
+
+  public void testDecode() {
+    assertDecodes(new UIntegerLexicoder(), Integer.MIN_VALUE);
+    assertDecodes(new UIntegerLexicoder(), -1);
+    assertDecodes(new UIntegerLexicoder(), 0);
+    assertDecodes(new UIntegerLexicoder(), 1);
+    assertDecodes(new UIntegerLexicoder(), Integer.MAX_VALUE);
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java
index acf0fb3..bca8b1d 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/ULongLexicoderTest.java
@@ -16,9 +16,11 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
 import java.util.Arrays;
 
-public class ULongLexicoderTest extends LexicoderTest {
+public class ULongLexicoderTest extends AbstractLexicoderTest {
 
   public void testEncoding() {
     ULongLexicoder ull = new ULongLexicoder();
@@ -50,4 +52,13 @@ public class ULongLexicoderTest extends LexicoderTest {
         Arrays.asList(0l, 0x01l, 0x1234l, 0x123456l, 0x12345678l, 
0x1234567890l, 0x1234567890abl, 0x1234567890abcdl, 0x1234567890abcdefl, 
Long.MAX_VALUE));
   }
 
+  public void testDecodes() {
+    assertDecodes(new ULongLexicoder(), Long.MIN_VALUE);
+    assertDecodes(new ULongLexicoder(), -1l);
+    assertDecodes(new ULongLexicoder(), 0l);
+    assertDecodes(new ULongLexicoder(), 1l);
+    assertDecodes(new ULongLexicoder(), 2l);
+    assertDecodes(new ULongLexicoder(), Long.MAX_VALUE);
+  }
+
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java
index 26c1476..60c89a3 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/UUIDLexicoderTest.java
@@ -16,11 +16,13 @@
  */
 package org.apache.accumulo.core.client.lexicoder;
 
+import org.apache.accumulo.core.client.lexicoder.impl.AbstractLexicoderTest;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.UUID;
 
-public class UUIDLexicoderTest extends LexicoderTest {
+public class UUIDLexicoderTest extends AbstractLexicoderTest {
   public void testSortOrder() {
 
     assertSortOrder(new UUIDLexicoder(),
@@ -36,4 +38,9 @@ public class UUIDLexicoderTest extends LexicoderTest {
 
     assertSortOrder(new UUIDLexicoder(), uuids);
   }
+
+  public void testDecodes() {
+    assertDecodes(new UUIDLexicoder(), UUID.randomUUID());
+
+  }
 }

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoderTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoderTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoderTest.java
new file mode 100644
index 0000000..502d132
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/AbstractLexicoderTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.accumulo.core.client.lexicoder.impl;
+
+import org.apache.accumulo.core.client.lexicoder.LexicoderTest;
+import org.apache.commons.lang.ArrayUtils;
+
+/**
+ * Assists in Testing classes that extend {@link 
org.apache.accumulo.core.client.lexicoder.AbstractEncoder}.  It
+ * references methods not formally defined in the {@link 
org.apache.accumulo.core.client.lexicoder.Lexicoder} interface.
+ * @since 1.7.0
+ */
+public abstract class AbstractLexicoderTest extends LexicoderTest {
+
+  public static <T> void assertDecodes(AbstractLexicoder<T> lexicoder, T 
expected) {
+    LexicoderTest.assertDecodes(lexicoder, expected);
+
+    byte[] encoded = lexicoder.encode(expected);
+
+    assertOutOfBoundsFails(lexicoder, encoded);
+
+    // munge bytes at start and end, then use offset and length to decode
+    final byte[] combined = ArrayUtils.addAll(ArrayUtils.addAll(START_PAD, 
encoded), END_PAD);
+
+    int offset = START_PAD.length;
+    int len = encoded.length;
+    T result = lexicoder.decode(combined, offset, len);
+    assertEquals(expected, result);
+  }
+
+  public void assertDecodesB(AbstractLexicoder<byte[]> lexicoder, byte[] 
expected) {
+    super.assertDecodesB(lexicoder, expected);
+
+    byte[] encoded = lexicoder.encode(expected);
+
+    assertOutOfBoundsFails(lexicoder, encoded);
+
+    // munge bytes at start and end, then use offset and length to decode
+    final byte[] combined = ArrayUtils.addAll(ArrayUtils.addAll(START_PAD, 
encoded), END_PAD);
+
+    int offset = START_PAD.length;
+    int len = encoded.length;
+    byte[] result = lexicoder.decode(combined, offset, len);
+    assertEqualsB(expected, result);
+  }
+
+  protected static <T> void assertOutOfBoundsFails(AbstractLexicoder<T> 
lexicoder, byte[] encoded) {
+    // decode null; should fail
+    try {
+      lexicoder.decode(null, 0, encoded.length);
+      fail("Should throw on null bytes.");
+    } catch (NullPointerException e) {}
+
+    // decode out of bounds, expect an exception
+    try {
+      lexicoder.decode(encoded, 0, encoded.length + 1);
+      fail("Should throw on exceeding length.");
+    } catch (IllegalArgumentException e) {}
+
+    try {
+      lexicoder.decode(encoded, -1, encoded.length);
+      fail("Should throw on negative offset.");
+    } catch (IllegalArgumentException e) {}
+
+    try {
+      lexicoder.decode(encoded, encoded.length, 0);
+      fail("Should throw on offset==length.");
+    } catch (IllegalArgumentException e) {}
+
+    try {
+      lexicoder.decode(encoded, 0, -1);
+      fail("Should throw on negative length.");
+    } catch (IllegalArgumentException e) {}
+
+    try {
+      lexicoder.decode(encoded, 1, -1);
+      fail("Should throw on negative length, even if (offset+len) is within 
bounds.");
+    } catch (IllegalArgumentException e) {}
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtilsTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtilsTest.java
 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtilsTest.java
new file mode 100644
index 0000000..1304797
--- /dev/null
+++ 
b/core/src/test/java/org/apache/accumulo/core/client/lexicoder/impl/ByteUtilsTest.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.accumulo.core.client.lexicoder.impl;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ByteUtilsTest {
+
+  private final byte[] empty = new byte[0];
+  private final byte[] noSplits = "nosplits".getBytes();
+  private final byte[] splitAt5 = ("1234" + (char)0x00 + "56789").getBytes();
+
+  @Test
+  public void testSplit() throws Exception {
+    byte[][] result;
+
+    // always returns the original array itself
+    result = ByteUtils.split(empty);
+    Assert.assertEquals(1, result.length);
+    Assert.assertArrayEquals(empty, result[0]);
+
+    result = ByteUtils.split(noSplits);
+    Assert.assertEquals(1, result.length);
+    Assert.assertArrayEquals(noSplits, result[0]);
+
+    result = ByteUtils.split(splitAt5);
+    Assert.assertEquals(2, result.length);
+    Assert.assertArrayEquals("1234".getBytes(), result[0]);
+    Assert.assertArrayEquals("56789".getBytes(), result[1]);
+  }
+
+  public void testSplitWithOffset() {
+    int offset;
+    byte[][] result;
+
+    // still see both splits
+    offset = 4;
+    result = ByteUtils.split(splitAt5, offset, splitAt5.length - offset);
+    Assert.assertEquals(2, result.length);
+    Assert.assertArrayEquals(empty, result[0]);
+    Assert.assertArrayEquals("56789".getBytes(), result[1]);
+
+    // should only see 1 split at this offset
+    offset = 5;
+    result = ByteUtils.split(splitAt5, offset, splitAt5.length - offset);
+    Assert.assertEquals(1, result.length);
+    Assert.assertArrayEquals("56789".getBytes(), result[0]);
+
+    // still one split, but smaller ending
+    offset = 5;
+    int len = splitAt5.length - offset - 1;
+    result = ByteUtils.split(splitAt5, offset, len);
+    Assert.assertEquals(1, result.length);
+    Assert.assertArrayEquals("5678".getBytes(), result[0]);
+  }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java 
b/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java
index cdac2fb..26326a5 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/iterators/user/CombinerTest.java
@@ -746,6 +746,10 @@ public class CombinerTest {
       return new ArrayList<Long>();
     }
 
+    public List<Long> decode(byte[] b, int offset, int len) {
+      return new ArrayList<Long>();
+    }
+
   }
 
   @Test

http://git-wip-us.apache.org/repos/asf/accumulo/blob/6b94344d/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java
----------------------------------------------------------------------
diff --git 
a/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java
 
b/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java
index 5317c4d..e4c90a4 100644
--- 
a/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java
+++ 
b/server/base/src/main/java/org/apache/accumulo/server/replication/StatusCombiner.java
@@ -20,6 +20,8 @@ import java.io.IOException;
 import java.util.Iterator;
 import java.util.Map;
 
+import com.google.common.base.Preconditions;
+import org.apache.accumulo.core.client.lexicoder.AbstractEncoder;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Value;
 import org.apache.accumulo.core.iterators.IteratorEnvironment;
@@ -41,7 +43,7 @@ import com.google.protobuf.InvalidProtocolBufferException;
 public class StatusCombiner extends TypedValueCombiner<Status> {
   private static final Logger log = Logger.getLogger(StatusCombiner.class);
 
-  public static class StatusEncoder implements Encoder<Status> {
+  public static class StatusEncoder extends AbstractEncoder<Status> implements 
Encoder<Status> {
     private static final Logger log = Logger.getLogger(StatusEncoder.class);
 
     @Override
@@ -50,7 +52,9 @@ public class StatusCombiner extends 
TypedValueCombiner<Status> {
     }
 
     @Override
-    public Status decode(byte[] b) throws ValueFormatException {
+    public Status decode(byte[] b) {
+      // Override super because it calls decodeUnchecked, which is not as 
performant
+      Preconditions.checkNotNull(b, "cannot decode null byte array");
       try {
         return Status.parseFrom(b);
       } catch (InvalidProtocolBufferException e) {
@@ -58,6 +62,22 @@ public class StatusCombiner extends 
TypedValueCombiner<Status> {
         throw new ValueFormatException(e);
       }
     }
+
+    /**
+     * Makes a copy of the subarray of {@code b}, then passes it through 
{@link Status#parseFrom(byte[])}
+     */
+    @Override
+    protected Status decodeUnchecked(byte[] b, int offset, int len) throws 
ValueFormatException {
+      try {
+        // have to make a copy because Status lacks the method to do this 
efficiently
+        byte[] boundedArr = new byte[len];
+        System.arraycopy(b, offset, boundedArr, 0, len);
+        return Status.parseFrom(boundedArr);
+      } catch (InvalidProtocolBufferException e) {
+        log.error("Failed to parse Status protocol buffer", e);
+        throw new ValueFormatException(e);
+      }
+    }
   }
 
   @Override

Reply via email to