This is an automated email from the ASF dual-hosted git repository.

stoty pushed a commit to branch branch-2
in repository https://gitbox.apache.org/repos/asf/hbase.git


The following commit(s) were added to refs/heads/branch-2 by this push:
     new e7b48e43a8d HBASE-28627 REST ScannerModel doesn't support 
includeStartRow/includeStopRow (#6494)
e7b48e43a8d is described below

commit e7b48e43a8d9ab22200ca6bcabec7939b3e2feb6
Author: chandrasekhar-188k 
<[email protected]>
AuthorDate: Tue Feb 18 18:25:47 2025 +0530

    HBASE-28627 REST ScannerModel doesn't support 
includeStartRow/includeStopRow (#6494)
    
    includes HBASE-29125 and JSON addendum
    
    Signed-off-by: Istvan Toth <[email protected]>
---
 .../org/apache/hadoop/hbase/rest/Constants.java    |   3 +
 .../apache/hadoop/hbase/rest/ScannerResource.java  |   5 +-
 .../hadoop/hbase/rest/ScannerResultGenerator.java  |  11 +-
 .../apache/hadoop/hbase/rest/TableResource.java    |  10 +-
 .../hadoop/hbase/rest/model/ScannerModel.java      |  45 +++++++
 hbase-rest/src/main/protobuf/ScannerMessage.proto  |   2 +
 .../hadoop/hbase/rest/TestScannerResource.java     | 147 +++++++++++++++++++++
 .../hadoop/hbase/rest/client/TestRemoteTable.java  |  78 +++++++++++
 .../hadoop/hbase/rest/model/TestScannerModel.java  |  58 +++++++-
 9 files changed, 350 insertions(+), 9 deletions(-)

diff --git 
a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/Constants.java 
b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/Constants.java
index 8d606793be6..b3d603c660e 100644
--- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/Constants.java
+++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/Constants.java
@@ -112,4 +112,7 @@ public interface Constants {
   /** Configuration parameter to set rest client socket timeout */
   String REST_CLIENT_SOCKET_TIMEOUT = "hbase.rest.client.socket.timeout";
   int DEFAULT_REST_CLIENT_SOCKET_TIMEOUT = 30 * 1000;
+
+  String SCAN_INCLUDE_START_ROW = "includeStartRow";
+  String SCAN_INCLUDE_STOP_ROW = "includeStopRow";
 }
diff --git 
a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/ScannerResource.java 
b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/ScannerResource.java
index b8a290e0617..59b60982ef1 100644
--- a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/ScannerResource.java
+++ b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/ScannerResource.java
@@ -110,8 +110,9 @@ public class ScannerResource extends ResourceBase {
     try {
       Filter filter = ScannerResultGenerator.buildFilterFromModel(model);
       String tableName = tableResource.getName();
-      ScannerResultGenerator gen = new ScannerResultGenerator(tableName, spec, 
filter,
-        model.getCaching(), model.getCacheBlocks());
+      ScannerResultGenerator gen =
+        new ScannerResultGenerator(tableName, spec, filter, model.getCaching(),
+          model.getCacheBlocks(), model.isIncludeStartRow(), 
model.isIncludeStopRow());
       String id = gen.getID();
       ScannerInstanceResource instance =
         new ScannerInstanceResource(tableName, id, gen, model.getBatch());
diff --git 
a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/ScannerResultGenerator.java
 
b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/ScannerResultGenerator.java
index e6a242610d5..499b04801aa 100644
--- 
a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/ScannerResultGenerator.java
+++ 
b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/ScannerResultGenerator.java
@@ -63,13 +63,20 @@ public class ScannerResultGenerator extends ResultGenerator 
{
 
   public ScannerResultGenerator(final String tableName, final RowSpec rowspec, 
final Filter filter,
     final int caching, final boolean cacheBlocks) throws 
IllegalArgumentException, IOException {
+    this(tableName, rowspec, filter, caching, cacheBlocks, true, false);
+  }
+
+  public ScannerResultGenerator(final String tableName, final RowSpec rowspec, 
final Filter filter,
+    final int caching, final boolean cacheBlocks, boolean includeStartRow, 
boolean includeStopRow)
+    throws IOException {
     Table table = RESTServlet.getInstance().getTable(tableName);
     try {
       Scan scan;
       if (rowspec.hasEndRow()) {
-        scan = new Scan(rowspec.getStartRow(), rowspec.getEndRow());
+        scan = new Scan().withStartRow(rowspec.getStartRow(), includeStartRow)
+          .withStopRow(rowspec.getEndRow(), includeStopRow);
       } else {
-        scan = new Scan(rowspec.getStartRow());
+        scan = new Scan().withStartRow(rowspec.getStartRow(), includeStartRow);
       }
       if (rowspec.hasColumns()) {
         byte[][] columns = rowspec.getColumns();
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 334fcb6f5a1..61d517848b4 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
@@ -133,7 +133,9 @@ public class TableResource extends ResourceBase {
     @DefaultValue("true") @QueryParam(Constants.SCAN_CACHE_BLOCKS) boolean 
cacheBlocks,
     @DefaultValue("false") @QueryParam(Constants.SCAN_REVERSED) boolean 
reversed,
     @QueryParam(Constants.FILTER) String paramFilter,
-    @QueryParam(Constants.FILTER_B64) @Encoded String paramFilterB64) {
+    @QueryParam(Constants.FILTER_B64) @Encoded String paramFilterB64,
+    @DefaultValue("true") @QueryParam(Constants.SCAN_INCLUDE_START_ROW) 
boolean includeStartRow,
+    @DefaultValue("false") @QueryParam(Constants.SCAN_INCLUDE_STOP_ROW) 
boolean includeStopRow) {
     try {
       Filter prefixFilter = null;
       Scan tableScan = new Scan();
@@ -142,7 +144,7 @@ public class TableResource extends ResourceBase {
         byte[] prefixBytes = Bytes.toBytes(prefix);
         prefixFilter = new PrefixFilter(Bytes.toBytes(prefix));
         if (startRow.isEmpty()) {
-          tableScan.setStartRow(prefixBytes);
+          tableScan.withStartRow(prefixBytes, includeStartRow);
         }
       }
       if (LOG.isTraceEnabled()) {
@@ -156,9 +158,9 @@ public class TableResource extends ResourceBase {
       tableScan.setMaxVersions(maxVersions);
       tableScan.setTimeRange(startTime, endTime);
       if (!startRow.isEmpty()) {
-        tableScan.setStartRow(Bytes.toBytes(startRow));
+        tableScan.withStartRow(Bytes.toBytes(startRow), includeStartRow);
       }
-      tableScan.setStopRow(Bytes.toBytes(endRow));
+      tableScan.withStopRow(Bytes.toBytes(endRow), includeStopRow);
       for (String col : column) {
         byte[][] parts = CellUtil.parseColumn(Bytes.toBytes(col.trim()));
         if (parts.length == 1) {
diff --git 
a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java 
b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java
index c5a3df512c3..5171a24496d 100644
--- 
a/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java
+++ 
b/hbase-rest/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java
@@ -120,6 +120,41 @@ public class ScannerModel implements 
ProtobufMessageHandler, Serializable {
   private List<String> labels = new ArrayList<>();
   private boolean cacheBlocks = true;
 
+  @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = 
IncludeStartRowFilter.class)
+  private boolean includeStartRow = true;
+
+  @JsonInclude(value = JsonInclude.Include.NON_DEFAULT)
+  private boolean includeStopRow = false;
+
+  @XmlAttribute
+  public boolean isIncludeStopRow() {
+    return includeStopRow;
+  }
+
+  public void setIncludeStopRow(boolean includeStopRow) {
+    this.includeStopRow = includeStopRow;
+  }
+
+  @XmlAttribute
+  public boolean isIncludeStartRow() {
+    return includeStartRow;
+  }
+
+  public void setIncludeStartRow(boolean includeStartRow) {
+    this.includeStartRow = includeStartRow;
+  }
+
+  @edu.umd.cs.findbugs.annotations.SuppressWarnings(
+      value = { "EQ_CHECK_FOR_OPERAND_NOT_COMPATIBLE_WITH_THIS", 
"HE_EQUALS_NO_HASHCODE",
+        "HE_EQUALS_USE_HASHCODE" },
+      justification = "1.The supplied value from the JSON Value Filter is of 
Type Boolean, hence supressing the check, 2.hashCode method will not be 
invoked, hence supressing the check, 3.hashCode method will not be invoked, 
hence supressing the check")
+  private static class IncludeStartRowFilter {
+    @Override
+    public boolean equals(Object value) {
+      return Boolean.TRUE.equals(value);
+    }
+  }
+
   /**
    * Implement lazily-instantiated singleton as per recipe here:
    * http://literatejava.com/jvm/fastest-threadsafe-singleton-jvm/
@@ -726,6 +761,8 @@ public class ScannerModel implements 
ProtobufMessageHandler, Serializable {
         model.addLabel(label);
       }
     }
+    model.setIncludeStartRow(scan.includeStartRow());
+    model.setIncludeStopRow(scan.includeStopRow());
     return model;
   }
 
@@ -977,6 +1014,8 @@ public class ScannerModel implements 
ProtobufMessageHandler, Serializable {
         builder.addLabels(label);
     }
     builder.setCacheBlocks(cacheBlocks);
+    builder.setIncludeStartRow(includeStartRow);
+    builder.setIncludeStopRow(includeStopRow);
     return builder.build();
   }
 
@@ -1020,6 +1059,12 @@ public class ScannerModel implements 
ProtobufMessageHandler, Serializable {
     if (builder.hasCacheBlocks()) {
       this.cacheBlocks = builder.getCacheBlocks();
     }
+    if (builder.hasIncludeStartRow()) {
+      this.includeStartRow = builder.getIncludeStartRow();
+    }
+    if (builder.hasIncludeStopRow()) {
+      this.includeStopRow = builder.getIncludeStopRow();
+    }
     return this;
   }
 
diff --git a/hbase-rest/src/main/protobuf/ScannerMessage.proto 
b/hbase-rest/src/main/protobuf/ScannerMessage.proto
index 08e34081ca4..3f857741dca 100644
--- a/hbase-rest/src/main/protobuf/ScannerMessage.proto
+++ b/hbase-rest/src/main/protobuf/ScannerMessage.proto
@@ -30,4 +30,6 @@ message Scanner {
   optional int32 caching = 9;     // specifies REST scanner caching
   repeated string labels = 10;
   optional bool cacheBlocks = 11; // server side block caching hint
+  optional bool includeStartRow = 13;
+  optional bool includeStopRow = 14;
 }
diff --git 
a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestScannerResource.java
 
b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestScannerResource.java
index 4ebfce0b508..646328b1f49 100644
--- 
a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestScannerResource.java
+++ 
b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestScannerResource.java
@@ -392,4 +392,151 @@ public class TestScannerResource {
     Response response = client.delete("/" + TABLE + 
"/scanner/NONEXISTENT_SCAN");
     assertEquals(404, response.getCode());
   }
+
+  @Test
+  public void testScannerWithIncludeStartStopRowXML() throws IOException, 
JAXBException {
+    // new scanner
+    ScannerModel model = new ScannerModel();
+    model.addColumn(Bytes.toBytes(COLUMN_1));
+    model.setStartRow(Bytes.toBytes("aaa"));
+    model.setEndRow(Bytes.toBytes("aae"));
+    StringWriter writer = new StringWriter();
+    marshaller.marshal(model, writer);
+    byte[] body = Bytes.toBytes(writer.toString());
+
+    conf.set("hbase.rest.readonly", "false");
+    Response response = client.put("/" + TABLE + "/scanner", 
Constants.MIMETYPE_XML, body);
+    assertEquals(201, response.getCode());
+    String scannerURI = response.getLocation();
+    assertNotNull(scannerURI);
+
+    // get a cell set
+    response = client.get(scannerURI, Constants.MIMETYPE_XML);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
+    CellSetModel cellSet =
+      (CellSetModel) unmarshaller.unmarshal(new 
ByteArrayInputStream(response.getBody()));
+
+    assertEquals(4, countCellSet(cellSet));
+
+    // test with include the start row false
+    model.setIncludeStartRow(false);
+    writer = new StringWriter();
+    marshaller.marshal(model, writer);
+    body = Bytes.toBytes(writer.toString());
+
+    conf.set("hbase.rest.readonly", "false");
+    response = client.put("/" + TABLE + "/scanner", Constants.MIMETYPE_XML, 
body);
+    assertEquals(201, response.getCode());
+    scannerURI = response.getLocation();
+    assertNotNull(scannerURI);
+
+    // get a cell set
+    response = client.get(scannerURI, Constants.MIMETYPE_XML);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
+    cellSet = (CellSetModel) unmarshaller.unmarshal(new 
ByteArrayInputStream(response.getBody()));
+
+    assertEquals(3, countCellSet(cellSet));
+
+    // test with include stop row true and start row false
+    model.setIncludeStartRow(false);
+    model.setIncludeStopRow(true);
+    writer = new StringWriter();
+    marshaller.marshal(model, writer);
+    body = Bytes.toBytes(writer.toString());
+
+    conf.set("hbase.rest.readonly", "false");
+    response = client.put("/" + TABLE + "/scanner", Constants.MIMETYPE_XML, 
body);
+    assertEquals(201, response.getCode());
+    scannerURI = response.getLocation();
+    assertNotNull(scannerURI);
+
+    // get a cell set
+    response = client.get(scannerURI, Constants.MIMETYPE_XML);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
+    cellSet = (CellSetModel) unmarshaller.unmarshal(new 
ByteArrayInputStream(response.getBody()));
+
+    assertEquals(4, countCellSet(cellSet));
+
+    // test with including the start row true and stop row true
+    model.setIncludeStartRow(true);
+    model.setIncludeStopRow(true);
+    writer = new StringWriter();
+    marshaller.marshal(model, writer);
+    body = Bytes.toBytes(writer.toString());
+
+    conf.set("hbase.rest.readonly", "false");
+    response = client.put("/" + TABLE + "/scanner", Constants.MIMETYPE_XML, 
body);
+    assertEquals(201, response.getCode());
+    scannerURI = response.getLocation();
+    assertNotNull(scannerURI);
+
+    // get a cell set
+    response = client.get(scannerURI, Constants.MIMETYPE_XML);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_XML, response.getHeader("content-type"));
+    cellSet = (CellSetModel) unmarshaller.unmarshal(new 
ByteArrayInputStream(response.getBody()));
+
+    assertEquals(5, countCellSet(cellSet));
+  }
+
+  @Test
+  public void testScannerWithIncludeStartStopRowPB() throws IOException {
+    // new scanner
+    ScannerModel model = new ScannerModel();
+    model.addColumn(Bytes.toBytes(COLUMN_1));
+    model.setStartRow(Bytes.toBytes("aaa"));
+    model.setEndRow(Bytes.toBytes("aae"));
+
+    // test put operation is forbidden in read-only mode
+    conf.set("hbase.rest.readonly", "false");
+    Response response = client.put("/" + TABLE + "/scanner", 
Constants.MIMETYPE_PROTOBUF,
+      model.createProtobufOutput());
+    assertEquals(201, response.getCode());
+    String scannerURI = response.getLocation();
+    assertNotNull(scannerURI);
+
+    // get a cell set
+    response = client.get(scannerURI, Constants.MIMETYPE_PROTOBUF);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_PROTOBUF, 
response.getHeader("content-type"));
+    CellSetModel cellSet = new CellSetModel();
+    cellSet.getObjectFromMessage(response.getBody());
+    assertEquals(4, countCellSet(cellSet));
+
+    // test with include start row false
+    model.setIncludeStartRow(false);
+    response = client.put("/" + TABLE + "/scanner", 
Constants.MIMETYPE_PROTOBUF,
+      model.createProtobufOutput());
+    assertEquals(201, response.getCode());
+    scannerURI = response.getLocation();
+    assertNotNull(scannerURI);
+
+    // get a cell set
+    response = client.get(scannerURI, Constants.MIMETYPE_PROTOBUF);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_PROTOBUF, 
response.getHeader("content-type"));
+    cellSet = new CellSetModel();
+    cellSet.getObjectFromMessage(response.getBody());
+    assertEquals(3, countCellSet(cellSet));
+
+    // test with include stop row true
+    model.setIncludeStartRow(true);
+    model.setIncludeStopRow(true);
+    response = client.put("/" + TABLE + "/scanner", 
Constants.MIMETYPE_PROTOBUF,
+      model.createProtobufOutput());
+    assertEquals(201, response.getCode());
+    scannerURI = response.getLocation();
+    assertNotNull(scannerURI);
+
+    // get a cell set
+    response = client.get(scannerURI, Constants.MIMETYPE_PROTOBUF);
+    assertEquals(200, response.getCode());
+    assertEquals(Constants.MIMETYPE_PROTOBUF, 
response.getHeader("content-type"));
+    cellSet = new CellSetModel();
+    cellSet.getObjectFromMessage(response.getBody());
+    assertEquals(5, countCellSet(cellSet));
+  }
 }
diff --git 
a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/client/TestRemoteTable.java
 
b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/client/TestRemoteTable.java
index 3a19934d749..a0ec0bf1640 100644
--- 
a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/client/TestRemoteTable.java
+++ 
b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/client/TestRemoteTable.java
@@ -630,4 +630,82 @@ public class TestRemoteTable {
       Thread.sleep(trialPause);
     }
   }
+
+  @Test
+  public void testScanWithInlcudeStartStopRow() throws Exception {
+    int numTrials = 6;
+
+    // Truncate the test table for inserting test scenarios rows keys
+    TEST_UTIL.getAdmin().disableTable(TABLE);
+    TEST_UTIL.getAdmin().truncateTable(TABLE, false);
+    String row = "testrow";
+
+    try (Table table = TEST_UTIL.getConnection().getTable(TABLE)) {
+      List<Put> puts = new ArrayList<>();
+      Put put = null;
+      for (int i = 1; i <= numTrials; i++) {
+        put = new Put(Bytes.toBytes(row + i));
+        put.addColumn(COLUMN_1, QUALIFIER_1, TS_2, Bytes.toBytes("testvalue" + 
i));
+        puts.add(put);
+      }
+      table.put(puts);
+    }
+
+    remoteTable =
+      new RemoteHTable(new Client(new Cluster().add("localhost", 
REST_TEST_UTIL.getServletPort())),
+        TEST_UTIL.getConfiguration(), TABLE.toBytes());
+
+    Scan scan =
+      new Scan().withStartRow(Bytes.toBytes(row + 
"1")).withStopRow(Bytes.toBytes(row + "5"));
+
+    ResultScanner scanner = remoteTable.getScanner(scan);
+    Iterator<Result> resultIterator = scanner.iterator();
+    int counter = 0;
+    while (resultIterator.hasNext()) {
+      byte[] row1 = resultIterator.next().getRow();
+      System.out.println(Bytes.toString(row1));
+      counter++;
+    }
+    assertEquals(4, counter);
+
+    // test with include start row false
+    scan = new Scan().withStartRow(Bytes.toBytes(row + "1"), false)
+      .withStopRow(Bytes.toBytes(row + "5"));
+    scanner = remoteTable.getScanner(scan);
+    resultIterator = scanner.iterator();
+    counter = 0;
+    while (resultIterator.hasNext()) {
+      byte[] row1 = resultIterator.next().getRow();
+      System.out.println(Bytes.toString(row1));
+      counter++;
+    }
+    assertEquals(3, counter);
+
+    // test with include start row false and stop row true
+    scan = new Scan().withStartRow(Bytes.toBytes(row + "1"), false)
+      .withStopRow(Bytes.toBytes(row + "5"), true);
+    scanner = remoteTable.getScanner(scan);
+    resultIterator = scanner.iterator();
+    counter = 0;
+    while (resultIterator.hasNext()) {
+      byte[] row1 = resultIterator.next().getRow();
+      System.out.println(Bytes.toString(row1));
+      counter++;
+    }
+    assertEquals(4, counter);
+
+    // test with include start row true and stop row true
+    scan = new Scan().withStartRow(Bytes.toBytes(row + "1"), true)
+      .withStopRow(Bytes.toBytes(row + "5"), true);
+    scanner = remoteTable.getScanner(scan);
+    resultIterator = scanner.iterator();
+    counter = 0;
+    while (resultIterator.hasNext()) {
+      byte[] row1 = resultIterator.next().getRow();
+      System.out.println(Bytes.toString(row1));
+      counter++;
+    }
+    assertEquals(5, counter);
+  }
+
 }
diff --git 
a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/model/TestScannerModel.java
 
b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/model/TestScannerModel.java
index a7c87036e4f..b7b4da240eb 100644
--- 
a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/model/TestScannerModel.java
+++ 
b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/model/TestScannerModel.java
@@ -22,6 +22,7 @@ import static org.junit.Assert.assertTrue;
 
 import com.fasterxml.jackson.core.JsonParseException;
 import com.fasterxml.jackson.databind.JsonMappingException;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.apache.hadoop.hbase.HBaseClassTestRule;
 import org.apache.hadoop.hbase.rest.ScannerResultGenerator;
 import org.apache.hadoop.hbase.testclassification.RestTests;
@@ -61,7 +62,7 @@ public class TestScannerModel extends 
TestModelBase<ScannerModel> {
     AS_JSON = 
"{\"batch\":100,\"caching\":1000,\"cacheBlocks\":false,\"endRow\":\"enp5eng=\","
       + 
"\"endTime\":1245393318192,\"maxVersions\":2147483647,\"startRow\":\"YWJyYWNhZGFicmE=\","
       + 
"\"startTime\":1245219839331,\"column\":[\"Y29sdW1uMQ==\",\"Y29sdW1uMjpmb28=\"],"
-      + "\"labels\":[\"private\",\"public\"]" + "}";
+      + "\"labels\":[\"private\",\"public\"]}";
 
     AS_PB = 
"CgthYnJhY2FkYWJyYRIFenp5engaB2NvbHVtbjEaC2NvbHVtbjI6Zm9vIGQo47qL554kMLDi57mf"
       + "JDj/////B0joB1IHcHJpdmF0ZVIGcHVibGljWAA=";
@@ -147,4 +148,59 @@ public class TestScannerModel extends 
TestModelBase<ScannerModel> {
     model.setFilter(FILTER);
     ScannerResultGenerator.buildFilterFromModel(model);
   }
+
+  @Test
+  public void testToJsonWithIncludeStartRowAndIncludeStopRow() throws 
Exception {
+    String jsonStr =
+      
"{\"batch\":100,\"caching\":1000,\"cacheBlocks\":false,\"endRow\":\"enp5eng=\","
+        + 
"\"endTime\":1245393318192,\"maxVersions\":2147483647,\"startRow\":\"YWJyYWNhZGFicmE=\","
+        + 
"\"startTime\":1245219839331,\"column\":[\"Y29sdW1uMQ==\",\"Y29sdW1uMjpmb28=\"],"
+        + "\"labels\":[\"private\",\"public\"],"
+        + "\"includeStartRow\":false,\"includeStopRow\":true}";
+
+    ObjectNode expObj = mapper.readValue(jsonStr, ObjectNode.class);
+    ObjectNode actObj = mapper.readValue(
+      toJSON(buildTestModelWithIncludeStartRowAndIncludeStopRow(false, true)), 
ObjectNode.class);
+    assertEquals(expObj, actObj);
+
+    jsonStr = 
"{\"batch\":100,\"caching\":1000,\"cacheBlocks\":false,\"endRow\":\"enp5eng=\","
+      + 
"\"endTime\":1245393318192,\"maxVersions\":2147483647,\"startRow\":\"YWJyYWNhZGFicmE=\","
+      + 
"\"startTime\":1245219839331,\"column\":[\"Y29sdW1uMQ==\",\"Y29sdW1uMjpmb28=\"],"
+      + "\"labels\":[\"private\",\"public\"]," + "\"includeStopRow\":true}";
+
+    expObj = mapper.readValue(jsonStr, ObjectNode.class);
+    actObj = mapper.readValue(
+      toJSON(buildTestModelWithIncludeStartRowAndIncludeStopRow(true, true)), 
ObjectNode.class);
+    assertEquals(expObj, actObj);
+
+    jsonStr = 
"{\"batch\":100,\"caching\":1000,\"cacheBlocks\":false,\"endRow\":\"enp5eng=\","
+      + 
"\"endTime\":1245393318192,\"maxVersions\":2147483647,\"startRow\":\"YWJyYWNhZGFicmE=\","
+      + 
"\"startTime\":1245219839331,\"column\":[\"Y29sdW1uMQ==\",\"Y29sdW1uMjpmb28=\"],"
+      + "\"labels\":[\"private\",\"public\"]," + "\"includeStartRow\":false}";
+
+    expObj = mapper.readValue(jsonStr, ObjectNode.class);
+    actObj = mapper.readValue(
+      toJSON(buildTestModelWithIncludeStartRowAndIncludeStopRow(false, 
false)), ObjectNode.class);
+    assertEquals(expObj, actObj);
+
+  }
+
+  protected ScannerModel 
buildTestModelWithIncludeStartRowAndIncludeStopRow(boolean includeStartRow,
+    boolean includeStopRow) {
+    ScannerModel model = new ScannerModel();
+    model.setStartRow(START_ROW);
+    model.setEndRow(END_ROW);
+    model.addColumn(COLUMN1);
+    model.addColumn(COLUMN2);
+    model.setStartTime(START_TIME);
+    model.setEndTime(END_TIME);
+    model.setBatch(BATCH);
+    model.setCaching(CACHING);
+    model.addLabel(PRIVATE);
+    model.addLabel(PUBLIC);
+    model.setCacheBlocks(CACHE_BLOCKS);
+    model.setIncludeStartRow(includeStartRow);
+    model.setIncludeStopRow(includeStopRow);
+    return model;
+  }
 }

Reply via email to