1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.jexl3;
19
20 import org.apache.commons.jexl3.introspection.JexlMethod;
21
22 import java.lang.reflect.Array;
23 import java.lang.reflect.Constructor;
24 import java.lang.reflect.InvocationTargetException;
25 import java.lang.reflect.Method;
26 import java.math.BigDecimal;
27 import java.math.BigInteger;
28 import java.math.MathContext;
29 import java.util.Collection;
30 import java.util.Map;
31 import java.util.concurrent.atomic.AtomicBoolean;
32 import java.util.regex.Matcher;
33 import java.util.regex.Pattern;
34
35 import static java.lang.StrictMath.floor;
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61 public class JexlArithmetic {
62
63
64 public static class NullOperand extends ArithmeticException {
65 private static final long serialVersionUID = 4720876194840764770L;
66 }
67
68
69 protected static final BigDecimal BIGD_DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE);
70
71
72 protected static final BigDecimal BIGD_DOUBLE_MIN_VALUE = BigDecimal.valueOf(Double.MIN_VALUE);
73
74
75 protected static final BigInteger BIGI_LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE);
76
77
78 protected static final BigInteger BIGI_LONG_MIN_VALUE = BigInteger.valueOf(Long.MIN_VALUE);
79
80
81 protected static final int BIGD_SCALE = -1;
82
83
84 private final boolean strict;
85
86
87 private final MathContext mathContext;
88
89
90 private final int mathScale;
91
92
93 private final Constructor<? extends JexlArithmetic> ctor;
94
95
96
97
98
99
100
101
102 public JexlArithmetic(final boolean astrict) {
103 this(astrict, null, Integer.MIN_VALUE);
104 }
105
106
107
108
109
110
111
112
113
114 public JexlArithmetic(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
115 this.strict = astrict;
116 this.mathContext = bigdContext == null ? MathContext.DECIMAL128 : bigdContext;
117 this.mathScale = bigdScale == Integer.MIN_VALUE ? BIGD_SCALE : bigdScale;
118 Constructor<? extends JexlArithmetic> actor = null;
119 try {
120 actor = getClass().getConstructor(boolean.class, MathContext.class, int.class);
121 } catch (final Exception xany) {
122
123 }
124 this.ctor = actor;
125 }
126
127
128
129
130
131
132
133
134 public JexlArithmetic options(final JexlOptions options) {
135 if (options != null) {
136 final boolean ostrict = options.isStrictArithmetic();
137 MathContext bigdContext = options.getMathContext();
138 if (bigdContext == null) {
139 bigdContext = getMathContext();
140 }
141 int bigdScale = options.getMathScale();
142 if (bigdScale == Integer.MIN_VALUE) {
143 bigdScale = getMathScale();
144 }
145 if (ostrict != isStrict()
146 || bigdScale != getMathScale()
147 || bigdContext != getMathContext()) {
148 return createWithOptions(ostrict, bigdContext, bigdScale);
149 }
150 }
151 return this;
152 }
153
154
155
156
157
158
159
160
161
162 @Deprecated
163 public JexlArithmetic options(final JexlEngine.Options options) {
164 if (options != null) {
165 Boolean ostrict = options.isStrictArithmetic();
166 if (ostrict == null) {
167 ostrict = isStrict();
168 }
169 MathContext bigdContext = options.getArithmeticMathContext();
170 if (bigdContext == null) {
171 bigdContext = getMathContext();
172 }
173 int bigdScale = options.getArithmeticMathScale();
174 if (bigdScale == Integer.MIN_VALUE) {
175 bigdScale = getMathScale();
176 }
177 if (ostrict != isStrict()
178 || bigdScale != getMathScale()
179 || bigdContext != getMathContext()) {
180 return createWithOptions(ostrict, bigdContext, bigdScale);
181 }
182 }
183 return this;
184 }
185
186
187
188
189
190
191
192
193
194 public JexlArithmetic options(final JexlContext context) {
195 if (context instanceof JexlContext.OptionsHandle) {
196 return options(((JexlContext.OptionsHandle) context).getEngineOptions());
197 }
198 if (context instanceof JexlEngine.Options) {
199 return options((JexlEngine.Options) context);
200 }
201 return this;
202 }
203
204
205
206
207
208
209
210
211
212
213
214
215 protected JexlArithmetic createWithOptions(final boolean astrict, final MathContext bigdContext, final int bigdScale) {
216 if (ctor != null) {
217 try {
218 return ctor.newInstance(astrict, bigdContext, bigdScale);
219 } catch (IllegalAccessException | IllegalArgumentException
220 | InstantiationException | InvocationTargetException xany) {
221
222 }
223 }
224 return new JexlArithmetic(astrict, bigdContext, bigdScale);
225 }
226
227
228
229
230
231 public interface Uberspect {
232
233
234
235
236
237
238 boolean overloads(JexlOperator operator);
239
240
241
242
243
244
245
246
247 JexlMethod getOperator(JexlOperator operator, Object... arg);
248 }
249
250
251
252
253
254
255
256
257
258
259
260
261
262 public interface ArrayBuilder {
263
264
265
266
267
268
269 void add(Object value);
270
271
272
273
274
275
276
277 Object create(boolean extended);
278 }
279
280
281
282
283
284
285
286 public ArrayBuilder arrayBuilder(final int size) {
287 return new org.apache.commons.jexl3.internal.ArrayBuilder(size);
288 }
289
290
291
292
293
294 public interface SetBuilder {
295
296
297
298
299
300 void add(Object value);
301
302
303
304
305
306
307 Object create();
308 }
309
310
311
312
313
314
315
316 public SetBuilder setBuilder(final int size) {
317 return new org.apache.commons.jexl3.internal.SetBuilder(size);
318 }
319
320
321
322
323
324 public interface MapBuilder {
325
326
327
328
329
330
331 void put(Object key, Object value);
332
333
334
335
336
337
338 Object create();
339 }
340
341
342
343
344
345
346
347 public MapBuilder mapBuilder(final int size) {
348 return new org.apache.commons.jexl3.internal.MapBuilder(size);
349 }
350
351
352
353
354
355
356
357
358
359
360 public Iterable<?> createRange(final Object from, final Object to) throws ArithmeticException {
361 final long lfrom = toLong(from);
362 final long lto = toLong(to);
363 if ((lfrom >= Integer.MIN_VALUE && lfrom <= Integer.MAX_VALUE)
364 && (lto >= Integer.MIN_VALUE && lto <= Integer.MAX_VALUE)) {
365 return org.apache.commons.jexl3.internal.IntegerRange.create((int) lfrom, (int) lto);
366 }
367 return org.apache.commons.jexl3.internal.LongRange.create(lfrom, lto);
368 }
369
370
371
372
373
374
375 protected boolean isNullOperand(final Object value) {
376 return value == null;
377 }
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393 protected <T> T controlNullOperand(final boolean strictCast, final T defaultValue) {
394 if (strictCast) {
395 throw new NullOperand();
396 }
397 return defaultValue;
398 }
399
400
401
402
403
404
405
406
407 protected Object controlNullNullOperands(final JexlOperator operator) {
408 if (isStrict(operator)) {
409 throw new NullOperand();
410 }
411 return 0;
412 }
413
414
415
416
417
418
419
420
421
422 protected boolean toBoolean(final boolean strict, final Object val) {
423 return isNullOperand(val)? controlNullOperand(strict, false) : toBoolean(val);
424 }
425
426
427
428
429
430
431
432
433 public boolean toBoolean(final Object val) {
434 if (val instanceof Boolean) {
435 return ((Boolean) val);
436 }
437 if (val instanceof Number) {
438 final double number = toDouble(strict, val);
439 return !Double.isNaN(number) && number != 0.d;
440 }
441 if (val instanceof AtomicBoolean) {
442 return ((AtomicBoolean) val).get();
443 }
444 if (val instanceof String) {
445 final String strval = val.toString();
446 return !strval.isEmpty() && !"false".equals(strval);
447 }
448 if (val == null) {
449 return controlNullOperand(strict, false);
450 }
451
452 return true;
453 }
454
455
456
457
458
459
460
461
462
463
464
465
466 protected int toInteger(final boolean strict, final Object val) {
467 return isNullOperand(val)? controlNullOperand(strict, 0) : toInteger(val);
468 }
469
470
471
472
473
474
475
476
477
478
479 public int toInteger(final Object val) {
480 if (val instanceof Double) {
481 final double dval = (Double) val;
482 return Double.isNaN(dval)? 0 : (int) dval;
483 }
484 if (val instanceof Number) {
485 return ((Number) val).intValue();
486 }
487 if (val instanceof String) {
488 return parseInteger((String) val);
489 }
490 if (val instanceof Boolean) {
491 return ((Boolean) val) ? 1 : 0;
492 }
493 if (val instanceof AtomicBoolean) {
494 return ((AtomicBoolean) val).get() ? 1 : 0;
495 }
496 if (val instanceof Character) {
497 return ((Character) val);
498 }
499 if (val == null) {
500 return controlNullOperand(strict, 0);
501 }
502 throw new ArithmeticException("Integer coercion: "
503 + val.getClass().getName() + ":(" + val + ")");
504 }
505
506
507
508
509
510
511
512
513
514
515
516
517 protected long toLong(final boolean strict, final Object val) {
518 return isNullOperand(val)? controlNullOperand(strict, 0L) : toLong(val);
519 }
520
521
522
523
524
525
526
527
528
529
530 public long toLong(final Object val) {
531 if (val instanceof Double) {
532 final double dval = (Double) val;
533 return Double.isNaN(dval)? 0L : (long) dval;
534 }
535 if (val instanceof Number) {
536 return ((Number) val).longValue();
537 }
538 if (val instanceof String) {
539 return parseLong((String) val);
540 }
541 if (val instanceof Boolean) {
542 return ((Boolean) val) ? 1L : 0L;
543 }
544 if (val instanceof AtomicBoolean) {
545 return ((AtomicBoolean) val).get() ? 1L : 0L;
546 }
547 if (val instanceof Character) {
548 return ((Character) val);
549 }
550 if (val == null) {
551 return controlNullOperand(strict, 0L);
552 }
553 throw new ArithmeticException("Long coercion: "
554 + val.getClass().getName() + ":(" + val + ")");
555 }
556
557
558
559
560
561
562
563
564
565
566
567
568 protected BigInteger toBigInteger(final boolean strict, final Object val) {
569 return isNullOperand(val)? controlNullOperand(strict, BigInteger.ZERO) : toBigInteger(val);
570 }
571
572
573
574
575
576
577
578
579
580
581 public BigInteger toBigInteger(final Object val) {
582 if (val instanceof BigInteger) {
583 return (BigInteger) val;
584 }
585 if (val instanceof Double) {
586 final Double dval = (Double) val;
587 if (Double.isNaN(dval)) {
588 return BigInteger.ZERO;
589 }
590 return BigInteger.valueOf(dval.longValue());
591 }
592 if (val instanceof BigDecimal) {
593 return ((BigDecimal) val).toBigInteger();
594 }
595 if (val instanceof Number) {
596 return BigInteger.valueOf(((Number) val).longValue());
597 }
598 if (val instanceof Boolean) {
599 return BigInteger.valueOf(((Boolean) val) ? 1L : 0L);
600 }
601 if (val instanceof AtomicBoolean) {
602 return BigInteger.valueOf(((AtomicBoolean) val).get() ? 1L : 0L);
603 }
604 if (val instanceof String) {
605 return parseBigInteger((String) val);
606 }
607 if (val instanceof Character) {
608 final int i = ((Character) val);
609 return BigInteger.valueOf(i);
610 }
611 if (val == null) {
612 return controlNullOperand(strict, BigInteger.ZERO);
613 }
614 throw new ArithmeticException("BigInteger coercion: "
615 + val.getClass().getName() + ":(" + val + ")");
616 }
617
618
619
620
621
622
623
624
625
626
627
628
629 protected BigDecimal toBigDecimal(final boolean strict, final Object val) {
630 return isNullOperand(val)? controlNullOperand(strict, BigDecimal.ZERO) : toBigDecimal(val);
631 }
632
633
634
635
636
637
638
639
640
641
642 public BigDecimal toBigDecimal(final Object val) {
643 if (val instanceof BigDecimal) {
644 return roundBigDecimal((BigDecimal) val);
645 }
646 if (val instanceof Double) {
647 if (Double.isNaN(((Double) val))) {
648 return BigDecimal.ZERO;
649 }
650 return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
651 }
652 if (val instanceof Number) {
653 return roundBigDecimal(new BigDecimal(val.toString(), getMathContext()));
654 }
655 if (val instanceof Boolean) {
656 return BigDecimal.valueOf(((Boolean) val) ? 1. : 0.);
657 }
658 if (val instanceof AtomicBoolean) {
659 return BigDecimal.valueOf(((AtomicBoolean) val).get() ? 1L : 0L);
660 }
661 if (val instanceof String) {
662 final String string = (String) val;
663 if ("".equals(string)) {
664 return BigDecimal.ZERO;
665 }
666 return roundBigDecimal(new BigDecimal(string, getMathContext()));
667 }
668 if (val instanceof Character) {
669 final int i = ((Character) val);
670 return new BigDecimal(i);
671 }
672 if (val == null) {
673 return controlNullOperand(strict, BigDecimal.ZERO);
674 }
675 throw new ArithmeticException("BigDecimal coercion: "
676 + val.getClass().getName() + ":(" + val + ")");
677 }
678
679
680
681
682
683
684
685
686
687
688
689
690 protected double toDouble(final boolean strict, final Object val) {
691 return isNullOperand(val)? controlNullOperand(strict, 0.d) : toDouble(val);
692 }
693
694
695
696
697
698
699
700
701
702
703 public double toDouble(final Object val) {
704 if (val instanceof Double) {
705 return ((Double) val);
706 }
707 if (val instanceof Number) {
708
709
710 return Double.parseDouble(String.valueOf(val));
711 }
712 if (val instanceof Boolean) {
713 return ((Boolean) val) ? 1. : 0.;
714 }
715 if (val instanceof AtomicBoolean) {
716 return ((AtomicBoolean) val).get() ? 1. : 0.;
717 }
718 if (val instanceof String) {
719 return parseDouble((String) val);
720 }
721 if (val instanceof Character) {
722 return ((Character) val);
723 }
724 if (val == null) {
725 return controlNullOperand(strict, 0.d);
726 }
727 throw new ArithmeticException("Double coercion: "
728 + val.getClass().getName() + ":(" + val + ")");
729 }
730
731
732
733
734
735
736
737
738
739
740
741 protected String toString(final boolean strict, final Object val) {
742 return isNullOperand(val)? controlNullOperand(strict, "") : toString(val);
743 }
744
745
746
747
748
749
750
751
752
753 public String toString(final Object val) {
754 if (val instanceof Double) {
755 final Double dval = (Double) val;
756 if (Double.isNaN(dval)) {
757 return "";
758 }
759 return dval.toString();
760 }
761 return val == null? controlNullOperand(strict, "") : val.toString();
762 }
763
764
765
766
767
768
769
770 public boolean isStrict() {
771 return strict;
772 }
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787 public boolean isStrict(final JexlOperator operator) {
788 if (operator != null) {
789 switch (operator) {
790 case EQ:
791 case ARRAY_GET:
792 case ARRAY_SET:
793 case PROPERTY_GET:
794 case PROPERTY_SET:
795 case EMPTY:
796 case SIZE:
797 case CONTAINS:
798 return false;
799 default:
800 return isStrict();
801 }
802 }
803 return isStrict();
804 }
805
806
807
808
809
810
811 public MathContext getMathContext() {
812 return mathContext;
813 }
814
815
816
817
818
819
820 public int getMathScale() {
821 return mathScale;
822 }
823
824
825
826
827
828
829
830 protected BigDecimal roundBigDecimal(final BigDecimal number) {
831 final int mscale = getMathScale();
832 if (mscale >= 0) {
833 return number.setScale(mscale, getMathContext().getRoundingMode());
834 }
835 return number;
836 }
837
838
839
840
841
842
843
844
845 @Deprecated
846 protected Object controlNullNullOperands() {
847 if (isStrict()) {
848 throw new NullOperand();
849 }
850 return 0;
851 }
852
853
854
855
856
857
858
859 @Deprecated
860 protected void controlNullOperand() {
861 if (isStrict()) {
862 throw new NullOperand();
863 }
864 }
865
866
867
868
869
870
871
872 public static final Pattern FLOAT_PATTERN = Pattern.compile("^[+-]?\\d*(\\.\\d*)?([eE][+-]?\\d+)?$");
873
874
875
876
877
878
879
880
881 protected boolean isFloatingPointNumber(final Object val) {
882 if (val instanceof Float || val instanceof Double) {
883 return true;
884 }
885 if (val instanceof CharSequence) {
886 final Matcher m = FLOAT_PATTERN.matcher((CharSequence) val);
887
888
889 return m.matches() && (m.start(1) >= 0 || m.start(2) >= 0);
890 }
891 return false;
892 }
893
894
895
896
897
898
899
900 protected boolean isFloatingPoint(final Object o) {
901 return o instanceof Float || o instanceof Double;
902 }
903
904
905
906
907
908
909
910 protected boolean isNumberable(final Object o) {
911 return o instanceof Integer
912 || o instanceof Long
913 || o instanceof Byte
914 || o instanceof Short
915 || o instanceof Character;
916 }
917
918
919
920
921
922
923 public Object controlReturn(final Object returned) {
924 return returned;
925 }
926
927
928
929
930
931
932
933
934
935
936
937
938 public Number narrow(final Number original) {
939 return narrowNumber(original, null);
940 }
941
942
943
944
945
946
947
948
949 protected boolean narrowAccept(final Class<?> narrow, final Class<?> source) {
950 return narrow == null || narrow.equals(source);
951 }
952
953
954
955
956
957
958
959
960 public Number narrowNumber(final Number original, final Class<?> narrow) {
961 if (original == null) {
962 return null;
963 }
964 Number result = original;
965 if (original instanceof BigDecimal) {
966 final BigDecimal bigd = (BigDecimal) original;
967
968 if (bigd.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0
969 || bigd.compareTo(BIGD_DOUBLE_MIN_VALUE) < 0) {
970 return original;
971 }
972 try {
973 final long l = bigd.longValueExact();
974
975 if (narrowAccept(narrow, Integer.class)
976 && l <= Integer.MAX_VALUE
977 && l >= Integer.MIN_VALUE) {
978 return (int) l;
979 }
980 if (narrowAccept(narrow, Long.class)) {
981 return l;
982 }
983 } catch (final ArithmeticException xa) {
984
985 }
986 }
987 if (original instanceof Double || original instanceof Float) {
988 final double value = original.doubleValue();
989 if (narrowAccept(narrow, Float.class)
990 && value <= Float.MAX_VALUE
991 && value >= Float.MIN_VALUE) {
992 result = result.floatValue();
993 }
994
995 } else {
996 if (original instanceof BigInteger) {
997 final BigInteger bigi = (BigInteger) original;
998
999 if (bigi.compareTo(BIGI_LONG_MAX_VALUE) > 0
1000 || bigi.compareTo(BIGI_LONG_MIN_VALUE) < 0) {
1001 return original;
1002 }
1003 }
1004 final long value = original.longValue();
1005 if (narrowAccept(narrow, Byte.class)
1006 && value <= Byte.MAX_VALUE
1007 && value >= Byte.MIN_VALUE) {
1008
1009 result = (byte) value;
1010 } else if (narrowAccept(narrow, Short.class)
1011 && value <= Short.MAX_VALUE
1012 && value >= Short.MIN_VALUE) {
1013 result = (short) value;
1014 } else if (narrowAccept(narrow, Integer.class)
1015 && value <= Integer.MAX_VALUE
1016 && value >= Integer.MIN_VALUE) {
1017 result = (int) value;
1018 }
1019
1020 }
1021 return result;
1022 }
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038 protected Number narrowBigInteger(final Object lhs, final Object rhs, final BigInteger bigi) {
1039
1040 if ((isNumberable(lhs) || isNumberable(rhs))
1041 && bigi.compareTo(BIGI_LONG_MAX_VALUE) <= 0
1042 && bigi.compareTo(BIGI_LONG_MIN_VALUE) >= 0) {
1043
1044 final long l = bigi.longValue();
1045
1046 if (!(lhs instanceof Long || rhs instanceof Long)
1047 && l <= Integer.MAX_VALUE
1048 && l >= Integer.MIN_VALUE) {
1049 return (int) l;
1050 }
1051 return l;
1052 }
1053 return bigi;
1054 }
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065 protected Number narrowBigDecimal(final Object lhs, final Object rhs, final BigDecimal bigd) {
1066 if (isNumberable(lhs) || isNumberable(rhs)) {
1067 try {
1068 final long l = bigd.longValueExact();
1069
1070 if (l <= Integer.MAX_VALUE && l >= Integer.MIN_VALUE) {
1071 return (int) l;
1072 }
1073 return l;
1074 } catch (final ArithmeticException xa) {
1075
1076 }
1077 }
1078 return bigd;
1079 }
1080
1081
1082
1083
1084
1085
1086
1087
1088 public boolean narrowArguments(final Object[] args) {
1089 boolean narrowed = false;
1090 if (args != null) {
1091 for (int a = 0; a < args.length; ++a) {
1092 final Object arg = args[a];
1093 if (arg instanceof Number) {
1094 final Number narg = (Number) arg;
1095 final Number narrow = narrow(narg);
1096 if (!narg.equals(narrow)) {
1097 args[a] = narrow;
1098 narrowed = true;
1099 }
1100 }
1101 }
1102 }
1103 return narrowed;
1104 }
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114 protected Number narrowLong(final Object lhs, final Object rhs, final long r) {
1115 if (!(lhs instanceof Long || rhs instanceof Long) && (int) r == r) {
1116 return (int) r;
1117 }
1118 return r;
1119 }
1120
1121
1122
1123
1124
1125
1126
1127 protected Number asLongNumber(final Object value) {
1128 return value instanceof Long
1129 || value instanceof Integer
1130 || value instanceof Short
1131 || value instanceof Byte
1132 ? (Number) value
1133 : null;
1134 }
1135
1136
1137
1138
1139
1140
1141 public Object increment(final Object val) {
1142 return increment(val, 1);
1143 }
1144
1145
1146
1147
1148
1149
1150 public Object decrement(final Object val) {
1151 return increment(val, -1);
1152 }
1153
1154
1155
1156
1157
1158
1159
1160 protected Object increment(final Object val, final int incr) {
1161 if (val == null) {
1162 return incr;
1163 }
1164 if (val instanceof Integer) {
1165 return ((Integer) val) + incr;
1166 }
1167 if (val instanceof Double) {
1168 return ((Double) val) + incr;
1169 }
1170 if (val instanceof Long) {
1171 return ((Long) val) + incr;
1172 }
1173 if (val instanceof BigDecimal) {
1174 final BigDecimal bd = (BigDecimal) val;
1175 return bd.add(BigDecimal.valueOf(incr), this.mathContext);
1176 }
1177 if (val instanceof BigInteger) {
1178 final BigInteger bi = (BigInteger) val;
1179 return bi.add(BigInteger.valueOf(incr));
1180 }
1181 if (val instanceof Float) {
1182 return ((Float) val) + incr;
1183 }
1184 if (val instanceof Short) {
1185 return (short) (((Short) val) + incr);
1186 }
1187 if (val instanceof Byte) {
1188 return (byte) (((Byte) val) + incr);
1189 }
1190 throw new ArithmeticException("Object "+(incr < 0? "decrement":"increment")+":(" + val + ")");
1191 }
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204 public Object add(final Object left, final Object right) {
1205 if (left == null && right == null) {
1206 return controlNullNullOperands(JexlOperator.ADD);
1207 }
1208 final boolean strconcat = strict
1209 ? left instanceof String || right instanceof String
1210 : left instanceof String && right instanceof String;
1211 if (!strconcat) {
1212 try {
1213
1214 final Number ln = asLongNumber(left);
1215 final Number rn = asLongNumber(right);
1216 if (ln != null && rn != null) {
1217 final long x = ln.longValue();
1218 final long y = rn.longValue();
1219 final long result = x + y;
1220
1221 if (((x ^ result) & (y ^ result)) < 0) {
1222 return BigInteger.valueOf(x).add(BigInteger.valueOf(y));
1223 }
1224 return narrowLong(left, right, result);
1225 }
1226 final boolean strictCast = isStrict(JexlOperator.ADD);
1227
1228 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1229 final BigDecimal l = toBigDecimal(strictCast, left);
1230 final BigDecimal r = toBigDecimal(strictCast, right);
1231 final BigDecimal result = l.add(r, getMathContext());
1232 return narrowBigDecimal(left, right, result);
1233 }
1234
1235 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1236 final double l = toDouble(strictCast, left);
1237 final double r = toDouble(strictCast, right);
1238 return l + r;
1239 }
1240
1241 final BigInteger l = toBigInteger(strictCast, left);
1242 final BigInteger r = toBigInteger(strictCast, right);
1243 final BigInteger result = l.add(r);
1244 return narrowBigInteger(left, right, result);
1245 } catch (final ArithmeticException nfe) {
1246
1247 }
1248 }
1249 return (left == null? "" : toString(left)).concat(right == null ? "" : toString(right));
1250 }
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260 public Object divide(final Object left, final Object right) {
1261 if (left == null && right == null) {
1262 return controlNullNullOperands(JexlOperator.DIVIDE);
1263 }
1264
1265 final Number ln = asLongNumber(left);
1266 final Number rn = asLongNumber(right);
1267 if (ln != null && rn != null) {
1268 final long x = ln.longValue();
1269 final long y = rn.longValue();
1270 if (y == 0L) {
1271 throw new ArithmeticException("/");
1272 }
1273 final long result = x / y;
1274 return narrowLong(left, right, result);
1275 }
1276 final boolean strictCast = isStrict(JexlOperator.DIVIDE);
1277
1278 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1279 final BigDecimal l = toBigDecimal(strictCast, left);
1280 final BigDecimal r = toBigDecimal(strictCast, right);
1281 if (BigDecimal.ZERO.equals(r)) {
1282 throw new ArithmeticException("/");
1283 }
1284 final BigDecimal result = l.divide(r, getMathContext());
1285 return narrowBigDecimal(left, right, result);
1286 }
1287
1288 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1289 final double l = toDouble(strictCast, left);
1290 final double r = toDouble(strictCast, right);
1291 if (r == 0.0) {
1292 throw new ArithmeticException("/");
1293 }
1294 return l / r;
1295 }
1296
1297 final BigInteger l = toBigInteger(strictCast, left);
1298 final BigInteger r = toBigInteger(strictCast, right);
1299 if (BigInteger.ZERO.equals(r)) {
1300 throw new ArithmeticException("/");
1301 }
1302 final BigInteger result = l.divide(r);
1303 return narrowBigInteger(left, right, result);
1304 }
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314 public Object mod(final Object left, final Object right) {
1315 if (left == null && right == null) {
1316 return controlNullNullOperands(JexlOperator.MOD);
1317 }
1318
1319 final Number ln = asLongNumber(left);
1320 final Number rn = asLongNumber(right);
1321 if (ln != null && rn != null) {
1322 final long x = ln.longValue();
1323 final long y = rn.longValue();
1324 if (y == 0L) {
1325 throw new ArithmeticException("%");
1326 }
1327 final long result = x % y;
1328 return narrowLong(left, right, result);
1329 }
1330 final boolean strictCast = isStrict(JexlOperator.MOD);
1331
1332 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1333 final BigDecimal l = toBigDecimal(strictCast, left);
1334 final BigDecimal r = toBigDecimal(strictCast, right);
1335 if (BigDecimal.ZERO.equals(r)) {
1336 throw new ArithmeticException("%");
1337 }
1338 final BigDecimal remainder = l.remainder(r, getMathContext());
1339 return narrowBigDecimal(left, right, remainder);
1340 }
1341
1342 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1343 final double l = toDouble(strictCast, left);
1344 final double r = toDouble(strictCast, right);
1345 if (r == 0.0) {
1346 throw new ArithmeticException("%");
1347 }
1348 return l % r;
1349 }
1350
1351 final BigInteger l = toBigInteger(strictCast, left);
1352 final BigInteger r = toBigInteger(strictCast, right);
1353 if (BigInteger.ZERO.equals(r)) {
1354 throw new ArithmeticException("%");
1355 }
1356 final BigInteger result = l.mod(r);
1357 return narrowBigInteger(left, right, result);
1358 }
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368 @SuppressWarnings("MagicNumber")
1369 protected static boolean isMultiplyExact(final long x, final long y, final long r) {
1370 final long ax = Math.abs(x);
1371 final long ay = Math.abs(y);
1372 return !(((ax | ay) >>> (Integer.SIZE - 1) != 0)
1373 && (((y != 0) && (r / y != x))
1374 || (x == Long.MIN_VALUE && y == -1)));
1375 }
1376
1377
1378
1379
1380
1381
1382
1383
1384 public Object multiply(final Object left, final Object right) {
1385 if (left == null && right == null) {
1386 return controlNullNullOperands(JexlOperator.MULTIPLY);
1387 }
1388
1389 final Number ln = asLongNumber(left);
1390 final Number rn = asLongNumber(right);
1391 if (ln != null && rn != null) {
1392 final long x = ln.longValue();
1393 final long y = rn.longValue();
1394 final long result = x * y;
1395
1396 if (!isMultiplyExact(x, y, result)) {
1397 return BigInteger.valueOf(x).multiply(BigInteger.valueOf(y));
1398 }
1399 return narrowLong(left, right, result);
1400 }
1401 final boolean strictCast = isStrict(JexlOperator.MULTIPLY);
1402
1403 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1404 final BigDecimal l = toBigDecimal(strictCast, left);
1405 final BigDecimal r = toBigDecimal(strictCast, right);
1406 final BigDecimal result = l.multiply(r, getMathContext());
1407 return narrowBigDecimal(left, right, result);
1408 }
1409
1410 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1411 final double l = toDouble(strictCast, left);
1412 final double r = toDouble(strictCast, right);
1413 return l * r;
1414 }
1415
1416 final BigInteger l = toBigInteger(strictCast, left);
1417 final BigInteger r = toBigInteger(strictCast, right);
1418 final BigInteger result = l.multiply(r);
1419 return narrowBigInteger(left, right, result);
1420 }
1421
1422
1423
1424
1425
1426
1427
1428
1429 public Object subtract(final Object left, final Object right) {
1430 if (left == null && right == null) {
1431 return controlNullNullOperands(JexlOperator.SUBTRACT);
1432 }
1433
1434 final Number ln = asLongNumber(left);
1435 final Number rn = asLongNumber(right);
1436 if (ln != null && rn != null) {
1437 final long x = ln.longValue();
1438 final long y = rn.longValue();
1439 final long result = x - y;
1440
1441 if (((x ^ y) & (x ^ result)) < 0) {
1442 return BigInteger.valueOf(x).subtract(BigInteger.valueOf(y));
1443 }
1444 return narrowLong(left, right, result);
1445 }
1446 final boolean strictCast = isStrict(JexlOperator.SUBTRACT);
1447
1448 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1449 final BigDecimal l = toBigDecimal(strictCast, left);
1450 final BigDecimal r = toBigDecimal(strictCast, right);
1451 final BigDecimal result = l.subtract(r, getMathContext());
1452 return narrowBigDecimal(left, right, result);
1453 }
1454
1455 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) {
1456 final double l = toDouble(strictCast, left);
1457 final double r = toDouble(strictCast, right);
1458 return l - r;
1459 }
1460
1461 final BigInteger l = toBigInteger(strictCast, left);
1462 final BigInteger r = toBigInteger(strictCast, right);
1463 final BigInteger result = l.subtract(r);
1464 return narrowBigInteger(left, right, result);
1465 }
1466
1467
1468
1469
1470
1471
1472
1473
1474 public Object negate(final Object val) {
1475 if (val == null) {
1476 return null;
1477 }
1478 if (val instanceof Integer) {
1479 return -((Integer) val);
1480 }
1481 if (val instanceof Double) {
1482 return - ((Double) val);
1483 }
1484 if (val instanceof Long) {
1485 return -((Long) val);
1486 }
1487 if (val instanceof BigDecimal) {
1488 return ((BigDecimal) val).negate();
1489 }
1490 if (val instanceof BigInteger) {
1491 return ((BigInteger) val).negate();
1492 }
1493 if (val instanceof Float) {
1494 return -((Float) val);
1495 }
1496 if (val instanceof Short) {
1497 return (short) -((Short) val);
1498 }
1499 if (val instanceof Byte) {
1500 return (byte) -((Byte) val);
1501 }
1502 if (val instanceof Boolean) {
1503 return !(Boolean) val;
1504 }
1505 if (val instanceof AtomicBoolean) {
1506 return !((AtomicBoolean) val).get();
1507 }
1508 throw new ArithmeticException("Object negate:(" + val + ")");
1509 }
1510
1511
1512
1513
1514
1515
1516
1517
1518 public boolean isNegateStable() {
1519 return true;
1520 }
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530 public Object positivize(final Object val) {
1531 if (val == null) {
1532 return null;
1533 }
1534 if (val instanceof Short) {
1535 return ((Short) val).intValue();
1536 }
1537 if (val instanceof Byte) {
1538 return ((Byte) val).intValue();
1539 }
1540 if (val instanceof Number) {
1541 return val;
1542 }
1543 if (val instanceof Character) {
1544 return (int) (Character) val;
1545 }
1546 if (val instanceof Boolean) {
1547 return val;
1548 }
1549 if (val instanceof AtomicBoolean) {
1550 return ((AtomicBoolean) val).get();
1551 }
1552 throw new ArithmeticException("Object positivize:(" + val + ")");
1553 }
1554
1555
1556
1557
1558
1559
1560
1561
1562 public boolean isPositivizeStable() {
1563 return true;
1564 }
1565
1566
1567
1568
1569
1570
1571
1572 public boolean testPredicate(final Object object) {
1573 final boolean strictCast = isStrict(JexlOperator.CONDITION);
1574 return toBoolean(strictCast, object);
1575 }
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588 public Boolean contains(final Object container, final Object value) {
1589 if (value == null && container == null) {
1590
1591 return true;
1592 }
1593 if (value == null || container == null) {
1594
1595 return false;
1596 }
1597
1598 if (container instanceof java.util.regex.Pattern) {
1599 return ((java.util.regex.Pattern) container).matcher(value.toString()).matches();
1600 }
1601 if (container instanceof CharSequence) {
1602 return value.toString().matches(container.toString());
1603 }
1604
1605 if (container instanceof Map<?, ?>) {
1606 if (value instanceof Map<?, ?>) {
1607 return ((Map<?, ?>) container).keySet().containsAll(((Map<?, ?>) value).keySet());
1608 }
1609 return ((Map<?, ?>) container).containsKey(value);
1610 }
1611
1612 return collectionContains(container, value);
1613 }
1614
1615
1616
1617
1618
1619
1620
1621
1622 protected Boolean collectionContains(final Object collection, final Object value) {
1623
1624 final Object left = arrayWrap(collection);
1625 if (left instanceof Collection<?>) {
1626 final Object right = arrayWrap(value);
1627 if (right instanceof Collection<?>) {
1628 return ((Collection<?>) left).containsAll((Collection<?>) right);
1629 }
1630 return ((Collection<?>) left).contains(value);
1631 }
1632 return null;
1633 }
1634
1635
1636
1637
1638
1639
1640
1641
1642 private static Object arrayWrap(final Object container) {
1643 return container.getClass().isArray()
1644 ? new org.apache.commons.jexl3.internal.introspection.ArrayListWrapper(container)
1645 : container;
1646 }
1647
1648
1649
1650
1651
1652
1653
1654
1655 public Boolean endsWith(final Object left, final Object right) {
1656 if (left == null && right == null) {
1657
1658 return true;
1659 }
1660 if (left == null || right == null) {
1661
1662 return false;
1663 }
1664 if (left instanceof CharSequence) {
1665 return (toString(left)).endsWith(toString(right));
1666 }
1667 return null;
1668 }
1669
1670
1671
1672
1673
1674
1675
1676
1677 public Boolean startsWith(final Object left, final Object right) {
1678 if (left == null && right == null) {
1679
1680 return true;
1681 }
1682 if (left == null || right == null) {
1683
1684 return false;
1685 }
1686 if (left instanceof CharSequence) {
1687 return (toString(left)).startsWith(toString(right));
1688 }
1689 return null;
1690 }
1691
1692
1693
1694
1695
1696
1697
1698
1699 public Boolean empty(final Object object) {
1700 return object == null || isEmpty(object, false);
1701 }
1702
1703
1704
1705
1706
1707
1708
1709 public Boolean isEmpty(final Object object) {
1710 return isEmpty(object, object == null);
1711 }
1712
1713
1714
1715
1716
1717
1718
1719
1720 public Boolean isEmpty(final Object object, final Boolean def) {
1721 if (object != null) {
1722 if (object instanceof Number) {
1723 final double d = ((Number) object).doubleValue();
1724 return Double.isNaN(d) || d == 0.d;
1725 }
1726 if (object instanceof CharSequence) {
1727 return ((CharSequence) object).length() == 0;
1728 }
1729 if (object.getClass().isArray()) {
1730 return Array.getLength(object) == 0;
1731 }
1732 if (object instanceof Collection<?>) {
1733 return ((Collection<?>) object).isEmpty();
1734 }
1735
1736 if (object instanceof Map<?, ?>) {
1737 return ((Map<?, ?>) object).isEmpty();
1738 }
1739 }
1740 return def;
1741 }
1742
1743
1744
1745
1746
1747
1748
1749 public Integer size(final Object object) {
1750 return size(object, object == null? 0 : 1);
1751 }
1752
1753
1754
1755
1756
1757
1758
1759
1760 public Integer size(final Object object, final Integer def) {
1761 if (object instanceof CharSequence) {
1762 return ((CharSequence) object).length();
1763 }
1764 if (object.getClass().isArray()) {
1765 return Array.getLength(object);
1766 }
1767 if (object instanceof Collection<?>) {
1768 return ((Collection<?>) object).size();
1769 }
1770 if (object instanceof Map<?, ?>) {
1771 return ((Map<?, ?>) object).size();
1772 }
1773 return def;
1774 }
1775
1776
1777
1778
1779
1780
1781
1782
1783 public Object and(final Object left, final Object right) {
1784 final long l = toLong(left);
1785 final long r = toLong(right);
1786 return l & r;
1787 }
1788
1789
1790
1791
1792
1793
1794
1795
1796 public Object or(final Object left, final Object right) {
1797 final long l = toLong(left);
1798 final long r = toLong(right);
1799 return l | r;
1800 }
1801
1802
1803
1804
1805
1806
1807
1808
1809 public Object xor(final Object left, final Object right) {
1810 final long l = toLong(left);
1811 final long r = toLong(right);
1812 return l ^ r;
1813 }
1814
1815
1816
1817
1818
1819
1820
1821 public Object complement(final Object val) {
1822 final boolean strictCast = isStrict(JexlOperator.COMPLEMENT);
1823 final long l = toLong(strictCast, val);
1824 return ~l;
1825 }
1826
1827
1828
1829
1830
1831
1832
1833 public Object not(final Object val) {
1834 final boolean strictCast = isStrict(JexlOperator.NOT);
1835 return !toBoolean(strictCast, val);
1836 }
1837
1838
1839
1840
1841
1842
1843
1844
1845 public Object shiftLeft(final Object left, final Object right) {
1846 final long l = toLong(left);
1847 final int r = toInteger(right);
1848 return l << r;
1849 }
1850
1851
1852
1853
1854
1855
1856
1857
1858 public Object shiftRight(final Object left, final Object right) {
1859 final long l = toLong(left);
1860 final long r = toInteger(right);
1861 return l >> r;
1862 }
1863
1864
1865
1866
1867
1868
1869
1870
1871 public Object shiftRightUnsigned(final Object left, final Object right) {
1872 final long l = toLong(left);
1873 final long r = toInteger(right);
1874 return l >>> r;
1875 }
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886 @Deprecated
1887 protected int compare(final Object left, final Object right, final String symbol) {
1888 JexlOperator operator;
1889 try {
1890 operator = JexlOperator.valueOf(symbol);
1891 } catch (final IllegalArgumentException xill) {
1892
1893 operator = JexlOperator.EQ;
1894 }
1895 return doCompare(left, right, operator);
1896 }
1897
1898
1899
1900
1901
1902 private final boolean compare321 = computeCompare321(this);
1903 private static boolean computeCompare321(final JexlArithmetic arithmetic) {
1904 Class<?> arithmeticClass = arithmetic.getClass();
1905 while(arithmeticClass != JexlArithmetic.class) {
1906 try {
1907 Method cmp = arithmeticClass.getDeclaredMethod("compare", Object.class, Object.class, String.class);
1908 if (cmp.getDeclaringClass() != JexlArithmetic.class) {
1909 return true;
1910 }
1911 } catch (NoSuchMethodException xany) {
1912 arithmeticClass = arithmeticClass.getSuperclass();
1913 }
1914 }
1915 return false;
1916 }
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927 protected int compare(final Object left, final Object right, final JexlOperator operator) {
1928
1929
1930 return compare321
1931 ? compare(left, right, operator.toString())
1932 : doCompare(left, right, operator);
1933 }
1934
1935 private int doCompare(final Object left, final Object right, final JexlOperator operator) {
1936 final boolean strictCast = isStrict(operator);
1937 if (left != null && right != null) {
1938 if (left instanceof BigDecimal || right instanceof BigDecimal) {
1939 final BigDecimal l = toBigDecimal(strictCast, left);
1940 final BigDecimal r = toBigDecimal(strictCast, right);
1941 return l.compareTo(r);
1942 }
1943 if (left instanceof BigInteger || right instanceof BigInteger) {
1944 try {
1945 final BigInteger l = toBigInteger(strictCast, left);
1946 final BigInteger r = toBigInteger(strictCast, right);
1947 return l.compareTo(r);
1948 } catch (final ArithmeticException xconvert) {
1949
1950 }
1951 }
1952 if (isFloatingPoint(left) || isFloatingPoint(right)) {
1953 final double lhs = toDouble(strictCast, left);
1954 final double rhs = toDouble(strictCast, right);
1955 if (Double.isNaN(lhs)) {
1956 if (Double.isNaN(rhs)) {
1957 return 0;
1958 }
1959 return -1;
1960 }
1961 if (Double.isNaN(rhs)) {
1962
1963 return +1;
1964 }
1965 return Double.compare(lhs, rhs);
1966 }
1967 if (isNumberable(left) || isNumberable(right)) {
1968 try {
1969 final long lhs = toLong(strictCast, left);
1970 final long rhs = toLong(strictCast, right);
1971 return Long.compare(lhs, rhs);
1972 } catch (final ArithmeticException xconvert) {
1973
1974 }
1975 }
1976 if (left instanceof String || right instanceof String) {
1977 return toString(left).compareTo(toString(right));
1978 }
1979 if (JexlOperator.EQ == operator) {
1980 return left.equals(right) ? 0 : -1;
1981 }
1982 if (left instanceof Comparable<?>) {
1983 @SuppressWarnings("unchecked")
1984 final Comparable<Object> comparable = (Comparable<Object>) left;
1985 return comparable.compareTo(right);
1986 }
1987 }
1988 throw new ArithmeticException("Object comparison:(" + left + " " + operator + " " + right + ")");
1989 }
1990
1991
1992
1993
1994
1995
1996
1997
1998 public boolean equals(final Object left, final Object right) {
1999 if (left == right) {
2000 return true;
2001 }
2002 if (left == null || right == null) {
2003 return false;
2004 }
2005 final boolean strictCast = isStrict(JexlOperator.EQ);
2006 if (left instanceof Boolean || right instanceof Boolean) {
2007 return toBoolean(left) == toBoolean(strictCast, right);
2008 }
2009 return compare(left, right, JexlOperator.EQ) == 0;
2010 }
2011
2012
2013
2014
2015
2016
2017
2018
2019 public boolean lessThan(final Object left, final Object right) {
2020 if ((left == right) || (left == null) || (right == null)) {
2021 return false;
2022 }
2023 return compare(left, right, JexlOperator.LT) < 0;
2024
2025 }
2026
2027
2028
2029
2030
2031
2032
2033
2034 public boolean greaterThan(final Object left, final Object right) {
2035 if ((left == right) || left == null || right == null) {
2036 return false;
2037 }
2038 return compare(left, right, JexlOperator.GT) > 0;
2039 }
2040
2041
2042
2043
2044
2045
2046
2047
2048 public boolean lessThanOrEqual(final Object left, final Object right) {
2049 if (left == right) {
2050 return true;
2051 }
2052 if (left == null || right == null) {
2053 return false;
2054 }
2055 return compare(left, right, JexlOperator.LTE) <= 0;
2056 }
2057
2058
2059
2060
2061
2062
2063
2064
2065 public boolean greaterThanOrEqual(final Object left, final Object right) {
2066 if (left == right) {
2067 return true;
2068 }
2069 if (left == null || right == null) {
2070 return false;
2071 }
2072 return compare(left, right, JexlOperator.GTE) >= 0;
2073 }
2074
2075
2076
2077
2078
2079
2080
2081
2082 private double parseDouble(final String arg) throws ArithmeticException {
2083 try {
2084 return arg.isEmpty()? Double.NaN : Double.parseDouble(arg);
2085 } catch (final NumberFormatException e) {
2086 final ArithmeticException arithmeticException = new ArithmeticException("Double coercion: ("+ arg +")");
2087 arithmeticException.initCause(e);
2088 throw arithmeticException;
2089 }
2090 }
2091
2092
2093
2094
2095
2096
2097
2098
2099 private long parseLong(final String arg) throws ArithmeticException {
2100 final double d = parseDouble(arg);
2101 if (Double.isNaN(d)) {
2102 return 0L;
2103 }
2104 final double f = floor(d);
2105 if (d == f) {
2106 return (long) d;
2107 }
2108 throw new ArithmeticException("Long coercion: ("+ arg +")");
2109 }
2110
2111
2112
2113
2114
2115
2116
2117
2118 private int parseInteger(final String arg) throws ArithmeticException {
2119 final long l = parseLong(arg);
2120 final int i = (int) l;
2121 if (i == l) {
2122 return i;
2123 }
2124 throw new ArithmeticException("Int coercion: ("+ arg +")");
2125 }
2126
2127
2128
2129
2130
2131
2132
2133
2134 private BigInteger parseBigInteger(final String arg) throws ArithmeticException {
2135 if (arg.isEmpty()) {
2136 return BigInteger.ZERO;
2137 }
2138 try {
2139 return new BigInteger(arg);
2140 } catch (final NumberFormatException xformat) {
2141
2142 }
2143 return BigInteger.valueOf(parseLong(arg));
2144 }
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154 @Deprecated
2155 public final Object bitwiseAnd(final Object lhs, final Object rhs) {
2156 return and(lhs, rhs);
2157 }
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168 @Deprecated
2169 public final Object bitwiseOr(final Object lhs, final Object rhs) {
2170 return or(lhs, rhs);
2171 }
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182 @Deprecated
2183 public final Object bitwiseXor(final Object lhs, final Object rhs) {
2184 return xor(lhs, rhs);
2185 }
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195 @Deprecated
2196 public final Object logicalNot(final Object arg) {
2197 return not(arg);
2198 }
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209 @Deprecated
2210 public final Object matches(final Object lhs, final Object rhs) {
2211 return contains(rhs, lhs);
2212 }
2213 }