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 bc96a95c913 HBASE-28626 MultiRowRangeFilter deserialization fails in org.apache.hadoop.hbase.rest.model.ScannerModel (#5951) bc96a95c913 is described below commit bc96a95c913f6d53594e24535ee3a9a70f48cac7 Author: Istvan Toth <st...@apache.org> AuthorDate: Thu May 30 07:27:50 2024 +0200 HBASE-28626 MultiRowRangeFilter deserialization fails in org.apache.hadoop.hbase.rest.model.ScannerModel (#5951) Signed-off-by: Ankit Singhal <an...@apache.org> (cherry picked from commit cd0b29c0a8fed71ec7ccb9b05a2f9b1a65d07b64) --- .../hadoop/hbase/rest/model/ScannerModel.java | 86 +++++++++++++++++++++- .../hadoop/hbase/rest/TestScannersWithFilters.java | 15 ++++ 2 files changed, 97 insertions(+), 4 deletions(-) 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 44b489db436..a8c52148e89 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 @@ -23,10 +23,12 @@ import com.google.protobuf.Message; import java.io.IOException; import java.io.Serializable; import java.util.ArrayList; +import java.util.Arrays; import java.util.Base64; import java.util.List; import java.util.Map; import java.util.NavigableSet; +import java.util.Objects; import javax.xml.bind.annotation.XmlAttribute; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @@ -201,6 +203,79 @@ public class ScannerModel implements ProtobufMessageHandler, Serializable { } + /** + * This DTO omits the pseudo-getters in MultiRowRangeFilter.RowRange which break Jackson + * deserialization. It also avoids adding those as dummy JSON elements. + */ + static class RowRangeModel { + + protected byte[] startRow; + + protected boolean startRowInclusive = true; + + protected byte[] stopRow; + + protected boolean stopRowInclusive = false; + + public RowRangeModel() { + } + + public RowRangeModel(MultiRowRangeFilter.RowRange rr) { + this.startRow = rr.getStartRow(); + this.startRowInclusive = rr.isStartRowInclusive(); + this.stopRow = rr.getStopRow(); + this.stopRowInclusive = rr.isStopRowInclusive(); + } + + public MultiRowRangeFilter.RowRange build() { + return new MultiRowRangeFilter.RowRange(startRow, startRowInclusive, stopRow, + stopRowInclusive); + } + + public byte[] getStartRow() { + return startRow; + } + + public byte[] getStopRow() { + return stopRow; + } + + /** Returns if start row is inclusive. */ + public boolean isStartRowInclusive() { + return startRowInclusive; + } + + /** Returns if stop row is inclusive. */ + public boolean isStopRowInclusive() { + return stopRowInclusive; + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + result = prime * result + Arrays.hashCode(startRow); + result = prime * result + Arrays.hashCode(stopRow); + result = prime * result + Objects.hash(startRowInclusive, stopRowInclusive); + return result; + } + + @Override + public boolean equals(Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof RowRangeModel)) { + return false; + } + RowRangeModel other = (RowRangeModel) obj; + return Arrays.equals(startRow, other.startRow) + && startRowInclusive == other.startRowInclusive && Arrays.equals(stopRow, other.stopRow) + && stopRowInclusive == other.stopRowInclusive; + } + + } + // A grab bag of fields, would have been a union if this were C. // These are null by default and will only be serialized if set (non null). @XmlAttribute @@ -240,7 +315,7 @@ public class ScannerModel implements ProtobufMessageHandler, Serializable { @XmlElement public List<String> prefixes; @XmlElement - private List<RowRange> ranges; + private List<RowRangeModel> ranges; @XmlElement public List<Long> timestamps; @@ -331,8 +406,7 @@ public class ScannerModel implements ProtobufMessageHandler, Serializable { case MultiRowRangeFilter: this.ranges = new ArrayList<>(); for (RowRange range : ((MultiRowRangeFilter) filter).getRowRanges()) { - this.ranges.add(new RowRange(range.getStartRow(), range.isStartRowInclusive(), - range.getStopRow(), range.isStopRowInclusive())); + this.ranges.add(new RowRangeModel(range)); } break; case PageFilter: @@ -436,7 +510,11 @@ public class ScannerModel implements ProtobufMessageHandler, Serializable { } break; case MultiRowRangeFilter: { - filter = new MultiRowRangeFilter(ranges); + ArrayList<MultiRowRangeFilter.RowRange> rowRanges = new ArrayList<>(ranges.size()); + for (RowRangeModel rangeModel : ranges) { + rowRanges.add(rangeModel.build()); + } + filter = new MultiRowRangeFilter(rowRanges); } break; case PageFilter: diff --git a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestScannersWithFilters.java b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestScannersWithFilters.java index a6fe3ad3e21..0d01fc888c5 100644 --- a/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestScannersWithFilters.java +++ b/hbase-rest/src/test/java/org/apache/hadoop/hbase/rest/TestScannersWithFilters.java @@ -51,6 +51,7 @@ import org.apache.hadoop.hbase.filter.FilterList; import org.apache.hadoop.hbase.filter.FilterList.Operator; import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter; import org.apache.hadoop.hbase.filter.InclusiveStopFilter; +import org.apache.hadoop.hbase.filter.MultiRowRangeFilter; import org.apache.hadoop.hbase.filter.PageFilter; import org.apache.hadoop.hbase.filter.PrefixFilter; import org.apache.hadoop.hbase.filter.QualifierFilter; @@ -957,4 +958,18 @@ public class TestScannersWithFilters { new KeyValue(ROWS_TWO[3], FAMILIES[0], QUALIFIERS_TWO[0], VALUES[1]) }; verifyScanFull(s, kvs); } + + @Test + public void testMultiRowRangeFilter() throws Exception { + long expectedRows = 2; + long expectedKeys = colsPerRow; + List<MultiRowRangeFilter.RowRange> ranges = new ArrayList<>(); + // Both return only the third element, as the second one is deleted during initialization. + ranges.add(new MultiRowRangeFilter.RowRange(ROWS_ONE[1], true, ROWS_ONE[2], true)); + ranges.add(new MultiRowRangeFilter.RowRange(ROWS_TWO[0], false, ROWS_TWO[3], false)); + + Scan s = new Scan(); + s.setFilter(new MultiRowRangeFilter(ranges)); + verifyScan(s, expectedRows, expectedKeys); + } }