@@ -52,12 +52,20 @@ public static <X> Specification<X> startsWith(String field, String value) {
5252 return (root , cq , cb ) -> cb .like (cb .upper (getColumnPath (root , field )), EscapeCharacter .DEFAULT .escape (value ).toUpperCase () + "%" , EscapeCharacter .DEFAULT .getEscapeCharacter ());
5353 }
5454
55+ /**
56+ * Returns a specification where the field value is not equal within the given tolerance.
57+ */
5558 public static <X > Specification <X > notEqual (String field , Double value , Double tolerance ) {
5659 return (root , cq , cb ) -> {
5760 Expression <Double > doubleExpression = getColumnPath (root , field ).as (Double .class );
61+ /**
62+ * in order to be equal to doubleExpression, truncated value has to fit :
63+ * value <= doubleExpression < value + tolerance
64+ * therefore in order to be different at least one of the opposite comparison needs to be true :
65+ */
5866 return cb .or (
59- cb .greaterThan (doubleExpression , value + tolerance ),
60- cb .lessThanOrEqualTo (doubleExpression , value )
67+ cb .greaterThanOrEqualTo (doubleExpression , value + tolerance ),
68+ cb .lessThan (doubleExpression , value )
6169 );
6270 };
6371 }
@@ -142,6 +150,9 @@ private static <X> Specification<X> appendNumberFilterToSpecification(Specificat
142150 }
143151
144152 private static <X > Specification <X > createNumberPredicate (Specification <X > specification , ResourceFilterDTO resourceFilter , String value ) {
153+ // the reference for the comparison is the number of digits after the decimal point in filterValue
154+ // filterValue is truncated, not rounded
155+ // extra digits are ignored, but the user may add '0's after the decimal point in order to get a better precision
145156 String [] splitValue = value .split ("\\ ." );
146157 int numberOfDecimalAfterDot = 0 ;
147158 if (splitValue .length > 1 ) {
@@ -154,7 +165,7 @@ private static <X> Specification<X> createNumberPredicate(Specification<X> speci
154165 case LESS_THAN_OR_EQUAL ->
155166 specification .and (lessThanOrEqual (resourceFilter .column (), valueDouble , tolerance ));
156167 case GREATER_THAN_OR_EQUAL ->
157- specification .and (greaterThanOrEqual (resourceFilter .column (), valueDouble , tolerance ));
168+ specification .and (greaterThanOrEqual (resourceFilter .column (), valueDouble , 0.0 ));
158169 default ->
159170 throw new IllegalArgumentException ("The filter type " + resourceFilter .type () + " is not supported with the data type " + resourceFilter .dataType ());
160171 };
0 commit comments