@Override
  public List<TRowResult> scannerGetList(int id, int nbRows) throws IllegalArgument, IOError {
    LOG.debug("scannerGetList: id={}", id);
    ResultScannerWrapper resultScannerWrapper = getScanner(id);
    if (null == resultScannerWrapper) {
      String message = "scanner ID is invalid";
      LOG.warn(message);
      throw new IllegalArgument("scanner ID is invalid");
    }

    Result[] results;
    try {
      results = resultScannerWrapper.getScanner().next(nbRows);
      if (null == results) {
        return new ArrayList<>();
      }
    } catch (IOException e) {
      LOG.warn(e.getMessage(), e);
      throw getIOError(e);
    } finally {
      // Add scanner back to scannerMap; protects against case
      // where scanner expired during processing of request.
      scannerMap.put(id, resultScannerWrapper);
    }
    return ThriftUtilities.rowResultFromHBase(results, resultScannerWrapper.isColumnSorted());
  }
Note: this internal interface is slightly different from public APIs in regard to handling of
the qualifier. Here we differ from the public Java API in that null != byte[0]. Rather, we
respect qual == null as a request for the entire column family. The caller (
{@link #getVerTs(ByteBuffer, ByteBuffer, ByteBuffer, long, int, Map)}) interface IS consistent
in that the column is parse like normal.
hbase-thrift/src/main/java/org/apache/hadoop/hbase/thrift/ThriftHBaseServiceHandler.java