diff --git a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java index 77e5f8add57..a6e2e696b70 100644 --- a/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java +++ b/hbase-common/src/main/java/org/apache/hadoop/hbase/util/Bytes.java @@ -242,14 +242,24 @@ public class Bytes { } /** - * Returns a new byte array, copied from the passed ByteBuffer. - * @param bb A ByteBuffer + * Returns a new byte array, copied from the given {@code buf}, + * from the index 0 (inclusive) to the limit (exclusive), + * regardless of the current position. + * The position and the other index parameters are not changed. + * + * @param buf a byte buffer * @return the byte array + * @see #getBytes(ByteBuffer) */ - public static byte[] toBytes(ByteBuffer bb) { - int length = bb.limit(); - byte [] result = new byte[length]; - System.arraycopy(bb.array(), bb.arrayOffset(), result, 0, length); + public static byte[] toBytes(ByteBuffer buf) { + ByteBuffer dup = buf.duplicate(); + dup.position(0); + return readBytes(dup); + } + + private static byte[] readBytes(ByteBuffer buf) { + byte [] result = new byte[buf.remaining()]; + buf.get(result); return result; } @@ -309,16 +319,23 @@ public class Bytes { } /** - * Converts the given byte buffer, from its array offset to its limit, to - * a string. The position and the mark are ignored. + * Converts the given byte buffer to a printable representation, + * from the index 0 (inclusive) to the limit (exclusive), + * regardless of the current position. + * The position and the other index parameters are not changed. * * @param buf a byte buffer * @return a string representation of the buffer's binary contents + * @see #toBytes(ByteBuffer) + * @see #getBytes(ByteBuffer) */ public static String toStringBinary(ByteBuffer buf) { if (buf == null) return "null"; - return toStringBinary(buf.array(), buf.arrayOffset(), buf.limit()); + if (buf.hasArray()) { + return toStringBinary(buf.array(), buf.arrayOffset(), buf.limit()); + } + return toStringBinary(toBytes(buf)); } /** @@ -737,17 +754,16 @@ public class Bytes { } /** - * This method will get a sequence of bytes from pos -> limit, - * but will restore pos after. - * @param buf - * @return byte array + * Returns a new byte array, copied from the given {@code buf}, + * from the position (inclusive) to the limit (exclusive). + * The position and the other index parameters are not changed. + * + * @param buf a byte buffer + * @return the byte array + * @see #toBytes(ByteBuffer) */ public static byte[] getBytes(ByteBuffer buf) { - int savedPos = buf.position(); - byte [] newBytes = new byte[buf.remaining()]; - buf.get(newBytes); - buf.position(savedPos); - return newBytes; + return readBytes(buf.duplicate()); } /** diff --git a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java index aec5298eee4..97ee8b76975 100644 --- a/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java +++ b/hbase-common/src/test/java/org/apache/hadoop/hbase/util/TestBytes.java @@ -23,6 +23,7 @@ import java.io.DataInputStream; import java.io.DataOutputStream; import java.io.IOException; import java.math.BigDecimal; +import java.nio.ByteBuffer; import java.util.Arrays; import java.util.Random; @@ -172,6 +173,69 @@ public class TestBytes extends TestCase { return result; } + public void testToBytesForByteBuffer() { + byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + ByteBuffer target = ByteBuffer.wrap(array); + target.position(2); + target.limit(7); + + byte[] actual = Bytes.toBytes(target); + byte[] expected = { 0, 1, 2, 3, 4, 5, 6 }; + assertTrue(Arrays.equals(expected, actual)); + assertEquals(2, target.position()); + assertEquals(7, target.limit()); + + ByteBuffer target2 = target.slice(); + assertEquals(0, target2.position()); + assertEquals(5, target2.limit()); + + byte[] actual2 = Bytes.toBytes(target2); + byte[] expected2 = { 2, 3, 4, 5, 6 }; + assertTrue(Arrays.equals(expected2, actual2)); + assertEquals(0, target2.position()); + assertEquals(5, target2.limit()); + } + + public void testGetBytesForByteBuffer() { + byte[] array = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + ByteBuffer target = ByteBuffer.wrap(array); + target.position(2); + target.limit(7); + + byte[] actual = Bytes.getBytes(target); + byte[] expected = { 2, 3, 4, 5, 6 }; + assertTrue(Arrays.equals(expected, actual)); + assertEquals(2, target.position()); + assertEquals(7, target.limit()); + } + + public void testToStringBinaryForBytes() { + byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 }; + String actual = Bytes.toStringBinary(array); + String expected = "09azAZ@\\x01"; + assertEquals(expected, actual); + + String actual2 = Bytes.toStringBinary(array, 2, 3); + String expected2 = "azA"; + assertEquals(expected2, actual2); + } + + public void testToStringBinaryForArrayBasedByteBuffer() { + byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 }; + ByteBuffer target = ByteBuffer.wrap(array); + String actual = Bytes.toStringBinary(target); + String expected = "09azAZ@\\x01"; + assertEquals(expected, actual); + } + + public void testToStringBinaryForReadOnlyByteBuffer() { + byte[] array = { '0', '9', 'a', 'z', 'A', 'Z', '@', 1 }; + ByteBuffer target = ByteBuffer.wrap(array).asReadOnlyBuffer(); + String actual = Bytes.toStringBinary(target); + String expected = "09azAZ@\\x01"; + assertEquals(expected, actual); + } + public void testBinarySearch() throws Exception { byte [][] arr = { {1},