From 31848a32a67ff601677b773d190ec694ebb3a5f2 Mon Sep 17 00:00:00 2001 From: ChandraSekhar K Date: Sun, 20 Oct 2024 17:32:22 +0530 Subject: [PATCH] HBASE-28627 REST ScannerModel doesn't support includeStartRow/includeStopRow --- .../apache/hadoop/hbase/rest/Constants.java | 3 + .../hadoop/hbase/rest/ScannerResource.java | 5 +- .../hbase/rest/ScannerResultGenerator.java | 11 +- .../hadoop/hbase/rest/TableResource.java | 10 +- .../hadoop/hbase/rest/model/ScannerModel.java | 45 ++++++ .../src/main/protobuf/ScannerMessage.proto | 2 + .../hbase/rest/TestScannerResource.java | 147 ++++++++++++++++++ .../hbase/rest/client/TestRemoteTable.java | 78 ++++++++++ .../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 8d606793be64..b3d603c660ee 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 b8a290e06174..59b60982ef12 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 @@ Response update(final ScannerModel model, final boolean replace, final UriInfo u 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 e6a242610d51..499b04801aae 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 ScannerResultGenerator(final String tableName, final RowSpec rowspec, fin 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 b8543287c894..51648b8f7155 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 @@ -135,7 +135,9 @@ public TableScanResource getScanResource(final @PathParam("scanspec") String sca @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(); @@ -144,7 +146,7 @@ public TableScanResource getScanResource(final @PathParam("scanspec") String sca byte[] prefixBytes = Bytes.toBytes(prefix); prefixFilter = new PrefixFilter(Bytes.toBytes(prefix)); if (startRow.isEmpty()) { - tableScan.setStartRow(prefixBytes); + tableScan.withStartRow(prefixBytes, includeStartRow); } } if (LOG.isTraceEnabled()) { @@ -158,9 +160,9 @@ public TableScanResource getScanResource(final @PathParam("scanspec") String sca 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 c5a3df512c3c..5171a24496d2 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 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 static ScannerModel fromScan(Scan scan) throws Exception { model.addLabel(label); } } + model.setIncludeStartRow(scan.includeStartRow()); + model.setIncludeStopRow(scan.includeStopRow()); return model; } @@ -977,6 +1014,8 @@ public Message messageFromObject() { builder.addLabels(label); } builder.setCacheBlocks(cacheBlocks); + builder.setIncludeStartRow(includeStartRow); + builder.setIncludeStopRow(includeStopRow); return builder.build(); } @@ -1020,6 +1059,12 @@ public ProtobufMessageHandler getObjectFromMessage(CodedInputStream cis) throws 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 08e34081ca4e..3f857741dca0 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 4ebfce0b5089..646328b1f49e 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 void deleteNonExistent() throws IOException { 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 3a19934d749c..a0ec0bf1640b 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 void testLongLivedScan() throws Exception { 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 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 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 a7c87036e4fe..b7b4da240eb8 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 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 TestScannerModel() throws Exception { 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 @@ private void verifyException(final String FILTER) throws Exception { 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; + } }