You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by gx...@apache.org on 2018/09/12 02:42:17 UTC

[1/3] hbase git commit: HBASE-21174 [REST] Failed to parse empty qualifier in TableResource#getScanResource

Repository: hbase
Updated Branches:
  refs/heads/branch-2 d40348e8c -> 45cd6ae2d
  refs/heads/branch-2.0 2ee755b76 -> 46492be08
  refs/heads/master 5c1b325b5 -> 971c9a606


HBASE-21174 [REST] Failed to parse empty qualifier in TableResource#getScanResource

Signed-off-by: tedyu <yu...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/971c9a60
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/971c9a60
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/971c9a60

Branch: refs/heads/master
Commit: 971c9a60671f2024ba4ce5241f1b2c98729b0eef
Parents: 5c1b325
Author: Guangxu Cheng <gu...@gmail.com>
Authored: Mon Sep 10 23:30:21 2018 +0800
Committer: Guangxu Cheng <gu...@gmail.com>
Committed: Wed Sep 12 10:31:35 2018 +0800

----------------------------------------------------------------------
 .../apache/hadoop/hbase/rest/TableResource.java | 32 +++++-------
 .../apache/hadoop/hbase/rest/TestTableScan.java | 55 +++++++++++++++++---
 2 files changed, 63 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/971c9a60/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
----------------------------------------------------------------------
diff --git a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
index b52b91b..f2bc784 100644
--- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
+++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
@@ -27,6 +27,7 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.QueryParam;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.yetus.audience.InterfaceAudience;
 import org.slf4j.Logger;
@@ -123,7 +124,7 @@ public class TableResource extends ResourceBase {
       @QueryParam(Constants.SCAN_LIMIT) int userRequestedLimit,
       @DefaultValue("") @QueryParam(Constants.SCAN_START_ROW) String startRow,
       @DefaultValue("") @QueryParam(Constants.SCAN_END_ROW) String endRow,
-      @DefaultValue("") @QueryParam(Constants.SCAN_COLUMN) List<String> column,
+      @QueryParam(Constants.SCAN_COLUMN) List<String> column,
       @DefaultValue("1") @QueryParam(Constants.SCAN_MAX_VERSIONS) int maxVersions,
       @DefaultValue("-1") @QueryParam(Constants.SCAN_BATCH_SIZE) int batchSize,
       @DefaultValue("0") @QueryParam(Constants.SCAN_START_TIME) long startTime,
@@ -156,26 +157,21 @@ public class TableResource extends ResourceBase {
         tableScan.setStartRow(Bytes.toBytes(startRow));
       }
       tableScan.setStopRow(Bytes.toBytes(endRow));
-      for (String csplit : column) {
-        String[] familysplit = csplit.trim().split(":");
-        if (familysplit.length == 2) {
-          if (familysplit[1].length() > 0) {
-            if (LOG.isTraceEnabled()) {
-              LOG.trace("Scan family and column : " + familysplit[0] + "  " + familysplit[1]);
-            }
-            tableScan.addColumn(Bytes.toBytes(familysplit[0]), Bytes.toBytes(familysplit[1]));
-          } else {
-            tableScan.addFamily(Bytes.toBytes(familysplit[0]));
-            if (LOG.isTraceEnabled()) {
-              LOG.trace("Scan family : " + familysplit[0] + " and empty qualifier.");
-            }
-            tableScan.addColumn(Bytes.toBytes(familysplit[0]), null);
+      for (String col : column) {
+        byte [][] parts = CellUtil.parseColumn(Bytes.toBytes(col.trim()));
+        if (parts.length == 1) {
+          if (LOG.isTraceEnabled()) {
+            LOG.trace("Scan family : " + Bytes.toStringBinary(parts[0]));
           }
-        } else if (StringUtils.isNotEmpty(familysplit[0])) {
+          tableScan.addFamily(parts[0]);
+        } else if (parts.length == 2) {
           if (LOG.isTraceEnabled()) {
-            LOG.trace("Scan family : " + familysplit[0]);
+            LOG.trace("Scan family and column : " + Bytes.toStringBinary(parts[0])
+                + "  " + Bytes.toStringBinary(parts[1]));
           }
-          tableScan.addFamily(Bytes.toBytes(familysplit[0]));
+          tableScan.addColumn(parts[0], parts[1]);
+        } else {
+          throw new IllegalArgumentException("Invalid column specifier.");
         }
       }
       FilterList filterList = new FilterList();

http://git-wip-us.apache.org/repos/asf/hbase/blob/971c9a60/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
----------------------------------------------------------------------
diff --git a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
index 766d0b9..2bb6157 100644
--- a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
+++ b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
@@ -90,9 +90,11 @@ public class TestTableScan {
   private static final String CFB = "b";
   private static final String COLUMN_1 = CFA + ":1";
   private static final String COLUMN_2 = CFB + ":2";
+  private static final String COLUMN_EMPTY = CFA + ":";
   private static Client client;
   private static int expectedRows1;
   private static int expectedRows2;
+  private static int expectedRows3;
   private static Configuration conf;
 
   private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
@@ -109,12 +111,13 @@ public class TestTableScan {
       REST_TEST_UTIL.getServletPort()));
     Admin admin = TEST_UTIL.getAdmin();
     if (!admin.tableExists(TABLE)) {
-    HTableDescriptor htd = new HTableDescriptor(TABLE);
-    htd.addFamily(new HColumnDescriptor(CFA));
-    htd.addFamily(new HColumnDescriptor(CFB));
-    admin.createTable(htd);
-    expectedRows1 = TestScannerResource.insertData(conf, TABLE, COLUMN_1, 1.0);
-    expectedRows2 = TestScannerResource.insertData(conf, TABLE, COLUMN_2, 0.5);
+      HTableDescriptor htd = new HTableDescriptor(TABLE);
+      htd.addFamily(new HColumnDescriptor(CFA));
+      htd.addFamily(new HColumnDescriptor(CFB));
+      admin.createTable(htd);
+      expectedRows1 = TestScannerResource.insertData(conf, TABLE, COLUMN_1, 1.0);
+      expectedRows2 = TestScannerResource.insertData(conf, TABLE, COLUMN_2, 0.5);
+      expectedRows3 = TestScannerResource.insertData(conf, TABLE, COLUMN_EMPTY, 1.0);
     }
   }
 
@@ -598,6 +601,46 @@ public class TestTableScan {
     }
   }
 
+  @Test
+  public void testColumnWithEmptyQualifier() throws IOException, JAXBException {
+    // Test scanning with empty qualifier
+    StringBuilder builder = new StringBuilder();
+    builder.append("/*");
+    builder.append("?");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_EMPTY);
+    Response response = client.get("/" + TABLE + builder.toString(),
+        Constants.MIMETYPE_JSON);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
+    ObjectMapper mapper = new JacksonJaxbJsonProvider()
+        .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE);
+    CellSetModel model = mapper.readValue(response.getStream(), CellSetModel.class);
+    int count = TestScannerResource.countCellSet(model);
+    assertEquals(expectedRows3, count);
+    checkRowsNotNull(model);
+    RowModel startRow = model.getRows().get(0);
+    assertEquals("aaa", Bytes.toString(startRow.getKey()));
+    assertEquals(1, startRow.getCells().size());
+
+    // Test scanning with empty qualifier and normal qualifier
+    builder = new StringBuilder();
+    builder.append("/*");
+    builder.append("?");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_1);
+    builder.append("&");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_EMPTY);
+    response = client.get("/" + TABLE + builder.toString(),
+        Constants.MIMETYPE_JSON);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
+    mapper = new JacksonJaxbJsonProvider()
+        .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE);
+    model = mapper.readValue(response.getStream(), CellSetModel.class);
+    count = TestScannerResource.countCellSet(model);
+    assertEquals(expectedRows1 + expectedRows3, count);
+    checkRowsNotNull(model);
+  }
+
   public static class CustomFilter extends PrefixFilter {
     private byte[] key = null;
 


[2/3] hbase git commit: HBASE-21174 [REST] Failed to parse empty qualifier in TableResource#getScanResource

Posted by gx...@apache.org.
HBASE-21174 [REST] Failed to parse empty qualifier in TableResource#getScanResource

Signed-off-by: tedyu <yu...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/45cd6ae2
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/45cd6ae2
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/45cd6ae2

Branch: refs/heads/branch-2
Commit: 45cd6ae2d9b43c7e50c6b27493ef6acf19c33dd8
Parents: d40348e
Author: Guangxu Cheng <gu...@gmail.com>
Authored: Mon Sep 10 23:30:21 2018 +0800
Committer: Guangxu Cheng <gu...@gmail.com>
Committed: Wed Sep 12 10:37:40 2018 +0800

----------------------------------------------------------------------
 .../apache/hadoop/hbase/rest/TableResource.java | 32 +++++-------
 .../apache/hadoop/hbase/rest/TestTableScan.java | 55 +++++++++++++++++---
 2 files changed, 63 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/45cd6ae2/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
----------------------------------------------------------------------
diff --git a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
index b52b91b..f2bc784 100644
--- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
+++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
@@ -27,6 +27,7 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.QueryParam;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.yetus.audience.InterfaceAudience;
 import org.slf4j.Logger;
@@ -123,7 +124,7 @@ public class TableResource extends ResourceBase {
       @QueryParam(Constants.SCAN_LIMIT) int userRequestedLimit,
       @DefaultValue("") @QueryParam(Constants.SCAN_START_ROW) String startRow,
       @DefaultValue("") @QueryParam(Constants.SCAN_END_ROW) String endRow,
-      @DefaultValue("") @QueryParam(Constants.SCAN_COLUMN) List<String> column,
+      @QueryParam(Constants.SCAN_COLUMN) List<String> column,
       @DefaultValue("1") @QueryParam(Constants.SCAN_MAX_VERSIONS) int maxVersions,
       @DefaultValue("-1") @QueryParam(Constants.SCAN_BATCH_SIZE) int batchSize,
       @DefaultValue("0") @QueryParam(Constants.SCAN_START_TIME) long startTime,
@@ -156,26 +157,21 @@ public class TableResource extends ResourceBase {
         tableScan.setStartRow(Bytes.toBytes(startRow));
       }
       tableScan.setStopRow(Bytes.toBytes(endRow));
-      for (String csplit : column) {
-        String[] familysplit = csplit.trim().split(":");
-        if (familysplit.length == 2) {
-          if (familysplit[1].length() > 0) {
-            if (LOG.isTraceEnabled()) {
-              LOG.trace("Scan family and column : " + familysplit[0] + "  " + familysplit[1]);
-            }
-            tableScan.addColumn(Bytes.toBytes(familysplit[0]), Bytes.toBytes(familysplit[1]));
-          } else {
-            tableScan.addFamily(Bytes.toBytes(familysplit[0]));
-            if (LOG.isTraceEnabled()) {
-              LOG.trace("Scan family : " + familysplit[0] + " and empty qualifier.");
-            }
-            tableScan.addColumn(Bytes.toBytes(familysplit[0]), null);
+      for (String col : column) {
+        byte [][] parts = CellUtil.parseColumn(Bytes.toBytes(col.trim()));
+        if (parts.length == 1) {
+          if (LOG.isTraceEnabled()) {
+            LOG.trace("Scan family : " + Bytes.toStringBinary(parts[0]));
           }
-        } else if (StringUtils.isNotEmpty(familysplit[0])) {
+          tableScan.addFamily(parts[0]);
+        } else if (parts.length == 2) {
           if (LOG.isTraceEnabled()) {
-            LOG.trace("Scan family : " + familysplit[0]);
+            LOG.trace("Scan family and column : " + Bytes.toStringBinary(parts[0])
+                + "  " + Bytes.toStringBinary(parts[1]));
           }
-          tableScan.addFamily(Bytes.toBytes(familysplit[0]));
+          tableScan.addColumn(parts[0], parts[1]);
+        } else {
+          throw new IllegalArgumentException("Invalid column specifier.");
         }
       }
       FilterList filterList = new FilterList();

http://git-wip-us.apache.org/repos/asf/hbase/blob/45cd6ae2/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
----------------------------------------------------------------------
diff --git a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
index 766d0b9..2bb6157 100644
--- a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
+++ b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
@@ -90,9 +90,11 @@ public class TestTableScan {
   private static final String CFB = "b";
   private static final String COLUMN_1 = CFA + ":1";
   private static final String COLUMN_2 = CFB + ":2";
+  private static final String COLUMN_EMPTY = CFA + ":";
   private static Client client;
   private static int expectedRows1;
   private static int expectedRows2;
+  private static int expectedRows3;
   private static Configuration conf;
 
   private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
@@ -109,12 +111,13 @@ public class TestTableScan {
       REST_TEST_UTIL.getServletPort()));
     Admin admin = TEST_UTIL.getAdmin();
     if (!admin.tableExists(TABLE)) {
-    HTableDescriptor htd = new HTableDescriptor(TABLE);
-    htd.addFamily(new HColumnDescriptor(CFA));
-    htd.addFamily(new HColumnDescriptor(CFB));
-    admin.createTable(htd);
-    expectedRows1 = TestScannerResource.insertData(conf, TABLE, COLUMN_1, 1.0);
-    expectedRows2 = TestScannerResource.insertData(conf, TABLE, COLUMN_2, 0.5);
+      HTableDescriptor htd = new HTableDescriptor(TABLE);
+      htd.addFamily(new HColumnDescriptor(CFA));
+      htd.addFamily(new HColumnDescriptor(CFB));
+      admin.createTable(htd);
+      expectedRows1 = TestScannerResource.insertData(conf, TABLE, COLUMN_1, 1.0);
+      expectedRows2 = TestScannerResource.insertData(conf, TABLE, COLUMN_2, 0.5);
+      expectedRows3 = TestScannerResource.insertData(conf, TABLE, COLUMN_EMPTY, 1.0);
     }
   }
 
@@ -598,6 +601,46 @@ public class TestTableScan {
     }
   }
 
+  @Test
+  public void testColumnWithEmptyQualifier() throws IOException, JAXBException {
+    // Test scanning with empty qualifier
+    StringBuilder builder = new StringBuilder();
+    builder.append("/*");
+    builder.append("?");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_EMPTY);
+    Response response = client.get("/" + TABLE + builder.toString(),
+        Constants.MIMETYPE_JSON);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
+    ObjectMapper mapper = new JacksonJaxbJsonProvider()
+        .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE);
+    CellSetModel model = mapper.readValue(response.getStream(), CellSetModel.class);
+    int count = TestScannerResource.countCellSet(model);
+    assertEquals(expectedRows3, count);
+    checkRowsNotNull(model);
+    RowModel startRow = model.getRows().get(0);
+    assertEquals("aaa", Bytes.toString(startRow.getKey()));
+    assertEquals(1, startRow.getCells().size());
+
+    // Test scanning with empty qualifier and normal qualifier
+    builder = new StringBuilder();
+    builder.append("/*");
+    builder.append("?");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_1);
+    builder.append("&");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_EMPTY);
+    response = client.get("/" + TABLE + builder.toString(),
+        Constants.MIMETYPE_JSON);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
+    mapper = new JacksonJaxbJsonProvider()
+        .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE);
+    model = mapper.readValue(response.getStream(), CellSetModel.class);
+    count = TestScannerResource.countCellSet(model);
+    assertEquals(expectedRows1 + expectedRows3, count);
+    checkRowsNotNull(model);
+  }
+
   public static class CustomFilter extends PrefixFilter {
     private byte[] key = null;
 


[3/3] hbase git commit: HBASE-21174 [REST] Failed to parse empty qualifier in TableResource#getScanResource

Posted by gx...@apache.org.
HBASE-21174 [REST] Failed to parse empty qualifier in TableResource#getScanResource

Signed-off-by: tedyu <yu...@gmail.com>


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/46492be0
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/46492be0
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/46492be0

Branch: refs/heads/branch-2.0
Commit: 46492be087e5f076dc0eeea1dc33ea444f8af02d
Parents: 2ee755b
Author: Guangxu Cheng <gu...@gmail.com>
Authored: Mon Sep 10 23:30:21 2018 +0800
Committer: Guangxu Cheng <gu...@gmail.com>
Committed: Wed Sep 12 10:39:39 2018 +0800

----------------------------------------------------------------------
 .../apache/hadoop/hbase/rest/TableResource.java | 32 +++++-------
 .../apache/hadoop/hbase/rest/TestTableScan.java | 55 +++++++++++++++++---
 2 files changed, 63 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/46492be0/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
----------------------------------------------------------------------
diff --git a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
index b52b91b..f2bc784 100644
--- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
+++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/TableResource.java
@@ -27,6 +27,7 @@ import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
 import javax.ws.rs.QueryParam;
 import org.apache.commons.lang3.StringUtils;
+import org.apache.hadoop.hbase.CellUtil;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.yetus.audience.InterfaceAudience;
 import org.slf4j.Logger;
@@ -123,7 +124,7 @@ public class TableResource extends ResourceBase {
       @QueryParam(Constants.SCAN_LIMIT) int userRequestedLimit,
       @DefaultValue("") @QueryParam(Constants.SCAN_START_ROW) String startRow,
       @DefaultValue("") @QueryParam(Constants.SCAN_END_ROW) String endRow,
-      @DefaultValue("") @QueryParam(Constants.SCAN_COLUMN) List<String> column,
+      @QueryParam(Constants.SCAN_COLUMN) List<String> column,
       @DefaultValue("1") @QueryParam(Constants.SCAN_MAX_VERSIONS) int maxVersions,
       @DefaultValue("-1") @QueryParam(Constants.SCAN_BATCH_SIZE) int batchSize,
       @DefaultValue("0") @QueryParam(Constants.SCAN_START_TIME) long startTime,
@@ -156,26 +157,21 @@ public class TableResource extends ResourceBase {
         tableScan.setStartRow(Bytes.toBytes(startRow));
       }
       tableScan.setStopRow(Bytes.toBytes(endRow));
-      for (String csplit : column) {
-        String[] familysplit = csplit.trim().split(":");
-        if (familysplit.length == 2) {
-          if (familysplit[1].length() > 0) {
-            if (LOG.isTraceEnabled()) {
-              LOG.trace("Scan family and column : " + familysplit[0] + "  " + familysplit[1]);
-            }
-            tableScan.addColumn(Bytes.toBytes(familysplit[0]), Bytes.toBytes(familysplit[1]));
-          } else {
-            tableScan.addFamily(Bytes.toBytes(familysplit[0]));
-            if (LOG.isTraceEnabled()) {
-              LOG.trace("Scan family : " + familysplit[0] + " and empty qualifier.");
-            }
-            tableScan.addColumn(Bytes.toBytes(familysplit[0]), null);
+      for (String col : column) {
+        byte [][] parts = CellUtil.parseColumn(Bytes.toBytes(col.trim()));
+        if (parts.length == 1) {
+          if (LOG.isTraceEnabled()) {
+            LOG.trace("Scan family : " + Bytes.toStringBinary(parts[0]));
           }
-        } else if (StringUtils.isNotEmpty(familysplit[0])) {
+          tableScan.addFamily(parts[0]);
+        } else if (parts.length == 2) {
           if (LOG.isTraceEnabled()) {
-            LOG.trace("Scan family : " + familysplit[0]);
+            LOG.trace("Scan family and column : " + Bytes.toStringBinary(parts[0])
+                + "  " + Bytes.toStringBinary(parts[1]));
           }
-          tableScan.addFamily(Bytes.toBytes(familysplit[0]));
+          tableScan.addColumn(parts[0], parts[1]);
+        } else {
+          throw new IllegalArgumentException("Invalid column specifier.");
         }
       }
       FilterList filterList = new FilterList();

http://git-wip-us.apache.org/repos/asf/hbase/blob/46492be0/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
----------------------------------------------------------------------
diff --git a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
index 766d0b9..2bb6157 100644
--- a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
+++ b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestTableScan.java
@@ -90,9 +90,11 @@ public class TestTableScan {
   private static final String CFB = "b";
   private static final String COLUMN_1 = CFA + ":1";
   private static final String COLUMN_2 = CFB + ":2";
+  private static final String COLUMN_EMPTY = CFA + ":";
   private static Client client;
   private static int expectedRows1;
   private static int expectedRows2;
+  private static int expectedRows3;
   private static Configuration conf;
 
   private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
@@ -109,12 +111,13 @@ public class TestTableScan {
       REST_TEST_UTIL.getServletPort()));
     Admin admin = TEST_UTIL.getAdmin();
     if (!admin.tableExists(TABLE)) {
-    HTableDescriptor htd = new HTableDescriptor(TABLE);
-    htd.addFamily(new HColumnDescriptor(CFA));
-    htd.addFamily(new HColumnDescriptor(CFB));
-    admin.createTable(htd);
-    expectedRows1 = TestScannerResource.insertData(conf, TABLE, COLUMN_1, 1.0);
-    expectedRows2 = TestScannerResource.insertData(conf, TABLE, COLUMN_2, 0.5);
+      HTableDescriptor htd = new HTableDescriptor(TABLE);
+      htd.addFamily(new HColumnDescriptor(CFA));
+      htd.addFamily(new HColumnDescriptor(CFB));
+      admin.createTable(htd);
+      expectedRows1 = TestScannerResource.insertData(conf, TABLE, COLUMN_1, 1.0);
+      expectedRows2 = TestScannerResource.insertData(conf, TABLE, COLUMN_2, 0.5);
+      expectedRows3 = TestScannerResource.insertData(conf, TABLE, COLUMN_EMPTY, 1.0);
     }
   }
 
@@ -598,6 +601,46 @@ public class TestTableScan {
     }
   }
 
+  @Test
+  public void testColumnWithEmptyQualifier() throws IOException, JAXBException {
+    // Test scanning with empty qualifier
+    StringBuilder builder = new StringBuilder();
+    builder.append("/*");
+    builder.append("?");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_EMPTY);
+    Response response = client.get("/" + TABLE + builder.toString(),
+        Constants.MIMETYPE_JSON);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
+    ObjectMapper mapper = new JacksonJaxbJsonProvider()
+        .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE);
+    CellSetModel model = mapper.readValue(response.getStream(), CellSetModel.class);
+    int count = TestScannerResource.countCellSet(model);
+    assertEquals(expectedRows3, count);
+    checkRowsNotNull(model);
+    RowModel startRow = model.getRows().get(0);
+    assertEquals("aaa", Bytes.toString(startRow.getKey()));
+    assertEquals(1, startRow.getCells().size());
+
+    // Test scanning with empty qualifier and normal qualifier
+    builder = new StringBuilder();
+    builder.append("/*");
+    builder.append("?");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_1);
+    builder.append("&");
+    builder.append(Constants.SCAN_COLUMN + "=" + COLUMN_EMPTY);
+    response = client.get("/" + TABLE + builder.toString(),
+        Constants.MIMETYPE_JSON);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_JSON, response.getHeader("content-type"));
+    mapper = new JacksonJaxbJsonProvider()
+        .locateMapper(CellSetModel.class, MediaType.APPLICATION_JSON_TYPE);
+    model = mapper.readValue(response.getStream(), CellSetModel.class);
+    count = TestScannerResource.countCellSet(model);
+    assertEquals(expectedRows1 + expectedRows3, count);
+    checkRowsNotNull(model);
+  }
+
   public static class CustomFilter extends PrefixFilter {
     private byte[] key = null;