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);
+  }
 }

Reply via email to