001/* 002 * Copyright 2015-2024 Ping Identity Corporation 003 * All Rights Reserved. 004 */ 005/* 006 * Copyright 2015-2024 Ping Identity Corporation 007 * 008 * Licensed under the Apache License, Version 2.0 (the "License"); 009 * you may not use this file except in compliance with the License. 010 * You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, software 015 * distributed under the License is distributed on an "AS IS" BASIS, 016 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 017 * See the License for the specific language governing permissions and 018 * limitations under the License. 019 */ 020/* 021 * Copyright (C) 2015-2024 Ping Identity Corporation 022 * 023 * This program is free software; you can redistribute it and/or modify 024 * it under the terms of the GNU General Public License (GPLv2 only) 025 * or the terms of the GNU Lesser General Public License (LGPLv2.1 only) 026 * as published by the Free Software Foundation. 027 * 028 * This program is distributed in the hope that it will be useful, 029 * but WITHOUT ANY WARRANTY; without even the implied warranty of 030 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 031 * GNU General Public License for more details. 032 * 033 * You should have received a copy of the GNU General Public License 034 * along with this program; if not, see <http://www.gnu.org/licenses>. 035 */ 036package com.unboundid.ldap.sdk.unboundidds.jsonfilter; 037 038 039 040import java.math.BigDecimal; 041import java.util.ArrayList; 042import java.util.Arrays; 043import java.util.Collections; 044import java.util.HashSet; 045import java.util.LinkedHashMap; 046import java.util.List; 047import java.util.Set; 048 049import com.unboundid.util.Mutable; 050import com.unboundid.util.NotNull; 051import com.unboundid.util.StaticUtils; 052import com.unboundid.util.ThreadSafety; 053import com.unboundid.util.ThreadSafetyLevel; 054import com.unboundid.util.Validator; 055import com.unboundid.util.json.JSONArray; 056import com.unboundid.util.json.JSONBoolean; 057import com.unboundid.util.json.JSONException; 058import com.unboundid.util.json.JSONNumber; 059import com.unboundid.util.json.JSONObject; 060import com.unboundid.util.json.JSONString; 061import com.unboundid.util.json.JSONValue; 062 063 064 065/** 066 * This class provides an implementation of a JSON object filter that can be 067 * used to identify JSON objects that have at least one value for a specified 068 * field that is greater than a given value. 069 * <BR> 070 * <BLOCKQUOTE> 071 * <B>NOTE:</B> This class, and other classes within the 072 * {@code com.unboundid.ldap.sdk.unboundidds} package structure, are only 073 * supported for use against Ping Identity, UnboundID, and 074 * Nokia/Alcatel-Lucent 8661 server products. These classes provide support 075 * for proprietary functionality or for external specifications that are not 076 * considered stable or mature enough to be guaranteed to work in an 077 * interoperable way with other types of LDAP servers. 078 * </BLOCKQUOTE> 079 * <BR> 080 * The fields that are required to be included in a "greater than" filter are: 081 * <UL> 082 * <LI> 083 * {@code field} -- A field path specifier for the JSON field for which to 084 * make the determination. This may be either a single string or an array 085 * of strings as described in the "Targeting Fields in JSON Objects" section 086 * of the class-level documentation for {@link JSONObjectFilter}. 087 * </LI> 088 * <LI> 089 * {@code value} -- The value to use in the matching. It must be either a 090 * string (which will be compared against other strings using lexicographic 091 * comparison) or a number. 092 * </LI> 093 * </UL> 094 * The fields that may optionally be included in a "greater than" filter are: 095 * <UL> 096 * <LI> 097 * {@code allowEquals} -- Indicates whether to match JSON objects that have 098 * a value for the specified field that matches the provided value. If 099 * present, this field must have a Boolean value of either {@code true} (to 100 * indicate that it should be a "greater-than or equal to" filter) or 101 * {@code false} (to indicate that it should be a strict "greater-than" 102 * filter). If this is not specified, then the default behavior will be to 103 * perform a strict "greater-than" evaluation. 104 * </LI> 105 * <LI> 106 * {@code matchAllElements} -- Indicates whether all elements of an array 107 * must be greater than (or possibly equal to) the specified value. If 108 * present, this field must have a Boolean value of {@code true} (to 109 * indicate that all elements of the array must match the criteria for this 110 * filter) or {@code false} (to indicate that at least one element of the 111 * array must match the criteria for this filter). If this is not 112 * specified, then the default behavior will be to require only at least 113 * one matching element. This field will be ignored for JSON objects in 114 * which the specified field has a value that is not an array. 115 * </LI> 116 * <LI> 117 * {@code caseSensitive} -- Indicates whether string values should be 118 * treated in a case-sensitive manner. If present, this field must have a 119 * Boolean value of either {@code true} or {@code false}. If it is not 120 * provided, then a default value of {@code false} will be assumed so that 121 * strings are treated in a case-insensitive manner. 122 * </LI> 123 * </UL> 124 * <H2>Example</H2> 125 * The following is an example of a "greater than" filter that will match any 126 * JSON object with a top-level field named "salary" with a value that is 127 * greater than or equal to 50000: 128 * <PRE> 129 * { "filterType" : "greaterThan", 130 * "field" : "salary", 131 * "value" : 50000, 132 * "allowEquals" : true } 133 * </PRE> 134 * The above filter can be created with the code: 135 * <PRE> 136 * GreaterThanJSONObjectFilter filter = 137 * new GreaterThanJSONObjectFilter("salary", 50000); 138 * filter.setAllowEquals(true); 139 * </PRE> 140 */ 141@Mutable() 142@ThreadSafety(level=ThreadSafetyLevel.NOT_THREADSAFE) 143public final class GreaterThanJSONObjectFilter 144 extends JSONObjectFilter 145{ 146 /** 147 * The value that should be used for the filterType element of the JSON object 148 * that represents a "greater than" filter. 149 */ 150 @NotNull public static final String FILTER_TYPE = "greaterThan"; 151 152 153 154 /** 155 * The name of the JSON field that is used to specify the field in the target 156 * JSON object for which to make the determination. 157 */ 158 @NotNull public static final String FIELD_FIELD_PATH = "field"; 159 160 161 162 /** 163 * The name of the JSON field that is used to specify the value to use for 164 * the matching. 165 */ 166 @NotNull public static final String FIELD_VALUE = "value"; 167 168 169 170 /** 171 * The name of the JSON field that is used to indicate whether to match JSON 172 * objects with a value that is considered equal to the provided value. 173 */ 174 @NotNull public static final String FIELD_ALLOW_EQUALS = "allowEquals"; 175 176 177 178 /** 179 * The name of the JSON field that is used to indicate whether to match all 180 * elements of an array rather than just one or more. 181 */ 182 @NotNull public static final String FIELD_MATCH_ALL_ELEMENTS = 183 "matchAllElements"; 184 185 186 187 /** 188 * The name of the JSON field that is used to indicate whether string matching 189 * should be case-sensitive. 190 */ 191 @NotNull public static final String FIELD_CASE_SENSITIVE = "caseSensitive"; 192 193 194 195 /** 196 * The pre-allocated set of required field names. 197 */ 198 @NotNull private static final Set<String> REQUIRED_FIELD_NAMES = 199 Collections.unmodifiableSet(new HashSet<>( 200 Arrays.asList(FIELD_FIELD_PATH, FIELD_VALUE))); 201 202 203 204 /** 205 * The pre-allocated set of optional field names. 206 */ 207 @NotNull private static final Set<String> OPTIONAL_FIELD_NAMES = 208 Collections.unmodifiableSet(new HashSet<>( 209 Arrays.asList(FIELD_ALLOW_EQUALS, FIELD_MATCH_ALL_ELEMENTS, 210 FIELD_CASE_SENSITIVE))); 211 212 213 214 /** 215 * The serial version UID for this serializable class. 216 */ 217 private static final long serialVersionUID = -8397741931424599570L; 218 219 220 221 // Indicates whether to match equivalent values in addition to those that are 222 // strictly greater than the target value. 223 private volatile boolean allowEquals; 224 225 // Indicates whether string matching should be case-sensitive. 226 private volatile boolean caseSensitive; 227 228 // Indicates whether to match all elements of an array rather than just one or 229 // more. 230 private volatile boolean matchAllElements; 231 232 // The expected value for the target field. 233 @NotNull private volatile JSONValue value; 234 235 // The field path specifier for the target field. 236 @NotNull private volatile List<String> field; 237 238 239 240 /** 241 * Creates an instance of this filter type that can only be used for decoding 242 * JSON objects as "greater than" filters. It cannot be used as a regular 243 * "greater than" filter. 244 */ 245 GreaterThanJSONObjectFilter() 246 { 247 field = null; 248 value = null; 249 allowEquals = false; 250 matchAllElements = false; 251 caseSensitive = false; 252 } 253 254 255 256 /** 257 * Creates a new instance of this filter type with the provided information. 258 * 259 * @param field The field path specifier for the target field. 260 * @param value The expected value for the target field. 261 * @param allowEquals Indicates whether to match values that are equal 262 * to the provided value in addition to those that 263 * are strictly greater than that value. 264 * @param matchAllElements Indicates whether, if the value of the target 265 * field is an array, all elements of that array 266 * will be required to match the criteria of this 267 * filter. 268 * @param caseSensitive Indicates whether string matching should be 269 * case sensitive. 270 */ 271 private GreaterThanJSONObjectFilter(@NotNull final List<String> field, 272 @NotNull final JSONValue value, 273 final boolean allowEquals, 274 final boolean matchAllElements, 275 final boolean caseSensitive) 276 { 277 this.field = field; 278 this.value = value; 279 this.allowEquals = allowEquals; 280 this.matchAllElements = matchAllElements; 281 this.caseSensitive = caseSensitive; 282 } 283 284 285 286 /** 287 * Creates a new instance of this filter type with the provided information. 288 * 289 * @param field The name of the top-level field to target with this filter. 290 * It must not be {@code null} . See the class-level 291 * documentation for the {@link JSONObjectFilter} class for 292 * information about field path specifiers. 293 * @param value The target value for this filter. 294 */ 295 public GreaterThanJSONObjectFilter(@NotNull final String field, 296 final long value) 297 { 298 this(Collections.singletonList(field), new JSONNumber(value)); 299 } 300 301 302 303 /** 304 * Creates a new instance of this filter type with the provided information. 305 * 306 * @param field The name of the top-level field to target with this filter. 307 * It must not be {@code null} . See the class-level 308 * documentation for the {@link JSONObjectFilter} class for 309 * information about field path specifiers. 310 * @param value The target value for this filter. 311 */ 312 public GreaterThanJSONObjectFilter(@NotNull final String field, 313 final double value) 314 { 315 this(Collections.singletonList(field), new JSONNumber(value)); 316 } 317 318 319 320 /** 321 * Creates a new instance of this filter type with the provided information. 322 * 323 * @param field The name of the top-level field to target with this filter. 324 * It must not be {@code null} . See the class-level 325 * documentation for the {@link JSONObjectFilter} class for 326 * information about field path specifiers. 327 * @param value The target value for this filter. It must not be 328 * {@code null}. 329 */ 330 public GreaterThanJSONObjectFilter(@NotNull final String field, 331 @NotNull final String value) 332 { 333 this(Collections.singletonList(field), new JSONString(value)); 334 } 335 336 337 338 /** 339 * Creates a new instance of this filter type with the provided information. 340 * 341 * @param field The name of the top-level field to target with this filter. 342 * It must not be {@code null} . See the class-level 343 * documentation for the {@link JSONObjectFilter} class for 344 * information about field path specifiers. 345 * @param value The target value for this filter. It must not be 346 * {@code null}, and it must be either a {@link JSONNumber} or 347 * a {@link JSONString}. 348 */ 349 public GreaterThanJSONObjectFilter(@NotNull final String field, 350 @NotNull final JSONValue value) 351 { 352 this(Collections.singletonList(field), value); 353 } 354 355 356 357 /** 358 * Creates a new instance of this filter type with the provided information. 359 * 360 * @param field The field path specifier for this filter. It must not be 361 * {@code null} or empty. See the class-level documentation 362 * for the {@link JSONObjectFilter} class for information about 363 * field path specifiers. 364 * @param value The target value for this filter. It must not be 365 * {@code null}, and it must be either a {@link JSONNumber} or 366 * a {@link JSONString}. 367 */ 368 public GreaterThanJSONObjectFilter(@NotNull final List<String> field, 369 @NotNull final JSONValue value) 370 { 371 Validator.ensureNotNull(field); 372 Validator.ensureFalse(field.isEmpty()); 373 374 Validator.ensureNotNull(value); 375 Validator.ensureTrue((value instanceof JSONNumber) || 376 (value instanceof JSONString)); 377 378 this.field = Collections.unmodifiableList(new ArrayList<>(field)); 379 this.value = value; 380 381 allowEquals = false; 382 matchAllElements = false; 383 caseSensitive = false; 384 } 385 386 387 388 /** 389 * Retrieves the field path specifier for this filter. 390 * 391 * @return The field path specifier for this filter. 392 */ 393 @NotNull() 394 public List<String> getField() 395 { 396 return field; 397 } 398 399 400 401 /** 402 * Sets the field path specifier for this filter. 403 * 404 * @param field The field path specifier for this filter. It must not be 405 * {@code null} or empty. See the class-level documentation 406 * for the {@link JSONObjectFilter} class for information about 407 * field path specifiers. 408 */ 409 public void setField(@NotNull final String... field) 410 { 411 setField(StaticUtils.toList(field)); 412 } 413 414 415 416 /** 417 * Sets the field path specifier for this filter. 418 * 419 * @param field The field path specifier for this filter. It must not be 420 * {@code null} or empty. See the class-level documentation 421 * for the {@link JSONObjectFilter} class for information about 422 * field path specifiers. 423 */ 424 public void setField(@NotNull final List<String> field) 425 { 426 Validator.ensureNotNull(field); 427 Validator.ensureFalse(field.isEmpty()); 428 429 this.field = Collections.unmodifiableList(new ArrayList<>(field)); 430 } 431 432 433 434 /** 435 * Retrieves the target value for this filter. 436 * 437 * @return The target value for this filter. 438 */ 439 @NotNull() 440 public JSONValue getValue() 441 { 442 return value; 443 } 444 445 446 447 /** 448 * Specifies the target value for this filter. 449 * 450 * @param value The target value for this filter. 451 */ 452 public void setValue(final long value) 453 { 454 setValue(new JSONNumber(value)); 455 } 456 457 458 459 /** 460 * Specifies the target value for this filter. 461 * 462 * @param value The target value for this filter. 463 */ 464 public void setValue(final double value) 465 { 466 setValue(new JSONNumber(value)); 467 } 468 469 470 471 /** 472 * Specifies the target value for this filter. 473 * 474 * @param value The target value for this filter. It must not be 475 * {@code null}. 476 */ 477 public void setValue(@NotNull final String value) 478 { 479 Validator.ensureNotNull(value); 480 481 setValue(new JSONString(value)); 482 } 483 484 485 486 /** 487 * Specifies the target value for this filter. 488 * 489 * @param value The target value for this filter. It must not be 490 * {@code null}, and it must be either a {@link JSONNumber} or 491 * a {@link JSONString}. 492 */ 493 public void setValue(@NotNull final JSONValue value) 494 { 495 Validator.ensureNotNull(value); 496 Validator.ensureTrue((value instanceof JSONNumber) || 497 (value instanceof JSONString)); 498 499 this.value = value; 500 } 501 502 503 504 /** 505 * Indicates whether this filter will match values that are considered equal 506 * to the provided value in addition to those that are strictly greater than 507 * that value. 508 * 509 * @return {@code true} if this filter should behave like a "greater than or 510 * equal to" filter, or {@code false} if it should behave strictly 511 * like a "greater than" filter. 512 */ 513 public boolean allowEquals() 514 { 515 return allowEquals; 516 } 517 518 519 520 /** 521 * Specifies whether this filter should match values that are considered equal 522 * to the provided value in addition to those that are strictly greater than 523 * that value. 524 * 525 * @param allowEquals Indicates whether this filter should match values that 526 * are considered equal to the provided value in addition 527 * to those that are strictly greater than this value. 528 */ 529 public void setAllowEquals(final boolean allowEquals) 530 { 531 this.allowEquals = allowEquals; 532 } 533 534 535 536 /** 537 * Indicates whether, if the specified field has a value that is an array, to 538 * require all elements of that array to match the criteria for this filter 539 * rather than merely requiring at least one value to match. 540 * 541 * @return {@code true} if the criteria contained in this filter will be 542 * required to match all elements of an array, or {@code false} if 543 * merely one or more values will be required to match. 544 */ 545 public boolean matchAllElements() 546 { 547 return matchAllElements; 548 } 549 550 551 552 /** 553 * Specifies whether, if the value of the target field is an array, all 554 * elements of that array will be required to match the criteria of this 555 * filter. This will be ignored if the value of the target field is not an 556 * array. 557 * 558 * @param matchAllElements {@code true} to indicate that all elements of an 559 * array will be required to match the criteria of 560 * this filter, or {@code false} to indicate that 561 * merely one or more values will be required to 562 * match. 563 */ 564 public void setMatchAllElements(final boolean matchAllElements) 565 { 566 this.matchAllElements = matchAllElements; 567 } 568 569 570 571 /** 572 * Indicates whether string matching should be performed in a case-sensitive 573 * manner. 574 * 575 * @return {@code true} if string matching should be case sensitive, or 576 * {@code false} if not. 577 */ 578 public boolean caseSensitive() 579 { 580 return caseSensitive; 581 } 582 583 584 585 /** 586 * Specifies whether string matching should be performed in a case-sensitive 587 * manner. 588 * 589 * @param caseSensitive Indicates whether string matching should be 590 * case sensitive. 591 */ 592 public void setCaseSensitive(final boolean caseSensitive) 593 { 594 this.caseSensitive = caseSensitive; 595 } 596 597 598 599 /** 600 * {@inheritDoc} 601 */ 602 @Override() 603 @NotNull() 604 public String getFilterType() 605 { 606 return FILTER_TYPE; 607 } 608 609 610 611 /** 612 * {@inheritDoc} 613 */ 614 @Override() 615 @NotNull() 616 protected Set<String> getRequiredFieldNames() 617 { 618 return REQUIRED_FIELD_NAMES; 619 } 620 621 622 623 /** 624 * {@inheritDoc} 625 */ 626 @Override() 627 @NotNull() 628 protected Set<String> getOptionalFieldNames() 629 { 630 return OPTIONAL_FIELD_NAMES; 631 } 632 633 634 635 /** 636 * {@inheritDoc} 637 */ 638 @Override() 639 public boolean matchesJSONObject(@NotNull final JSONObject o) 640 { 641 final List<JSONValue> candidates = getValues(o, field); 642 if (candidates.isEmpty()) 643 { 644 return false; 645 } 646 647 for (final JSONValue v : candidates) 648 { 649 if (v instanceof JSONArray) 650 { 651 boolean matchOne = false; 652 boolean matchAll = true; 653 for (final JSONValue arrayValue : ((JSONArray) v).getValues()) 654 { 655 if (matches(arrayValue)) 656 { 657 if (! matchAllElements) 658 { 659 return true; 660 } 661 matchOne = true; 662 } 663 else 664 { 665 matchAll = false; 666 if (matchAllElements) 667 { 668 break; 669 } 670 } 671 } 672 673 if (matchAllElements && matchOne && matchAll) 674 { 675 return true; 676 } 677 } 678 else if (matches(v)) 679 { 680 return true; 681 } 682 } 683 684 return false; 685 } 686 687 688 689 /** 690 * Indicates whether the provided value matches the criteria of this filter. 691 * 692 * @param v The value for which to make the determination. 693 * 694 * @return {@code true} if the provided value matches the criteria of this 695 * filter, or {@code false} if not. 696 */ 697 private boolean matches(@NotNull final JSONValue v) 698 { 699 if ((v instanceof JSONNumber) && (value instanceof JSONNumber)) 700 { 701 final BigDecimal targetValue = ((JSONNumber) value).getValue(); 702 final BigDecimal objectValue = ((JSONNumber) v).getValue(); 703 if (allowEquals) 704 { 705 return (objectValue.compareTo(targetValue) >= 0); 706 } 707 else 708 { 709 return (objectValue.compareTo(targetValue) > 0); 710 } 711 } 712 else if ((v instanceof JSONString) && (value instanceof JSONString)) 713 { 714 final String targetValue = ((JSONString) value).stringValue(); 715 final String objectValue = ((JSONString) v).stringValue(); 716 if (allowEquals) 717 { 718 if (caseSensitive) 719 { 720 return (objectValue.compareTo(targetValue) >= 0); 721 } 722 else 723 { 724 return (objectValue.compareToIgnoreCase(targetValue) >= 0); 725 } 726 } 727 else 728 { 729 if (caseSensitive) 730 { 731 return (objectValue.compareTo(targetValue) > 0); 732 } 733 else 734 { 735 return (objectValue.compareToIgnoreCase(targetValue) > 0); 736 } 737 } 738 } 739 else 740 { 741 return false; 742 } 743 } 744 745 746 747 /** 748 * {@inheritDoc} 749 */ 750 @Override() 751 @NotNull() 752 public JSONObject toJSONObject() 753 { 754 final LinkedHashMap<String,JSONValue> fields = 755 new LinkedHashMap<>(StaticUtils.computeMapCapacity(6)); 756 757 fields.put(FIELD_FILTER_TYPE, new JSONString(FILTER_TYPE)); 758 759 if (field.size() == 1) 760 { 761 fields.put(FIELD_FIELD_PATH, new JSONString(field.get(0))); 762 } 763 else 764 { 765 final ArrayList<JSONValue> fieldNameValues = 766 new ArrayList<>(field.size()); 767 for (final String s : field) 768 { 769 fieldNameValues.add(new JSONString(s)); 770 } 771 fields.put(FIELD_FIELD_PATH, new JSONArray(fieldNameValues)); 772 } 773 774 fields.put(FIELD_VALUE, value); 775 776 if (allowEquals) 777 { 778 fields.put(FIELD_ALLOW_EQUALS, JSONBoolean.TRUE); 779 } 780 781 if (matchAllElements) 782 { 783 fields.put(FIELD_MATCH_ALL_ELEMENTS, JSONBoolean.TRUE); 784 } 785 786 if (caseSensitive) 787 { 788 fields.put(FIELD_CASE_SENSITIVE, JSONBoolean.TRUE); 789 } 790 791 return new JSONObject(fields); 792 } 793 794 795 796 /** 797 * {@inheritDoc} 798 */ 799 @Override() 800 @NotNull() 801 public JSONObject toNormalizedJSONObject() 802 { 803 final LinkedHashMap<String,JSONValue> fields = 804 new LinkedHashMap<>(StaticUtils.computeMapCapacity(6)); 805 806 fields.put(FIELD_FILTER_TYPE, new JSONString(FILTER_TYPE)); 807 808 if (field.size() == 1) 809 { 810 fields.put(FIELD_FIELD_PATH, new JSONString(field.get(0))); 811 } 812 else 813 { 814 final ArrayList<JSONValue> fieldNameValues = 815 new ArrayList<>(field.size()); 816 for (final String s : field) 817 { 818 fieldNameValues.add(new JSONString(s)); 819 } 820 fields.put(FIELD_FIELD_PATH, new JSONArray(fieldNameValues)); 821 } 822 823 fields.put(FIELD_VALUE, 824 value.toNormalizedValue(false, (! caseSensitive), false)); 825 826 if (allowEquals) 827 { 828 fields.put(FIELD_ALLOW_EQUALS, JSONBoolean.TRUE); 829 } 830 831 if (matchAllElements) 832 { 833 fields.put(FIELD_MATCH_ALL_ELEMENTS, JSONBoolean.TRUE); 834 } 835 836 if (caseSensitive) 837 { 838 fields.put(FIELD_CASE_SENSITIVE, JSONBoolean.TRUE); 839 } 840 841 return new JSONObject(fields); 842 } 843 844 845 846 /** 847 * {@inheritDoc} 848 */ 849 @Override() 850 @NotNull() 851 protected GreaterThanJSONObjectFilter decodeFilter( 852 @NotNull final JSONObject filterObject) 853 throws JSONException 854 { 855 final List<String> fieldPath = 856 getStrings(filterObject, FIELD_FIELD_PATH, false, null); 857 858 final boolean isAllowEquals = getBoolean(filterObject, 859 FIELD_ALLOW_EQUALS, false); 860 861 final boolean isMatchAllElements = getBoolean(filterObject, 862 FIELD_MATCH_ALL_ELEMENTS, false); 863 864 final boolean isCaseSensitive = getBoolean(filterObject, 865 FIELD_CASE_SENSITIVE, false); 866 867 return new GreaterThanJSONObjectFilter(fieldPath, 868 filterObject.getField(FIELD_VALUE), isAllowEquals, isMatchAllElements, 869 isCaseSensitive); 870 } 871}