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