001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.apache.commons.jexl3; 019 020import static java.lang.StrictMath.floor; 021import static org.apache.commons.jexl3.JexlOperator.EQ; 022 023import java.lang.reflect.Array; 024import java.lang.reflect.Constructor; 025import java.lang.reflect.InvocationTargetException; 026import java.lang.reflect.Method; 027import java.math.BigDecimal; 028import java.math.BigInteger; 029import java.math.MathContext; 030import java.util.Collection; 031import java.util.Map; 032import java.util.concurrent.atomic.AtomicBoolean; 033import java.util.function.Supplier; 034import java.util.function.ToLongFunction; 035import java.util.regex.Matcher; 036import java.util.regex.Pattern; 037 038import org.apache.commons.jexl3.introspection.JexlMethod; 039import org.apache.commons.logging.Log; 040 041/** 042 * Perform arithmetic, implements JexlOperator methods. 043 * 044 * <p>This is the class to derive to implement new operator behaviors.</p> 045 * 046 * <p>The 5 base arithmetic operators (+, - , *, /, %) follow the same evaluation rules regarding their arguments.</p> 047 * <ol> 048 * <li>If both are null, result is 0 if arithmetic (or operator) is non-strict, ArithmeticException is thrown 049 * otherwise</li> 050 * <li>If both arguments are numberable - any kind of integer including boolean -, coerce both to Long and coerce 051 * result to the most precise argument class ({@code boolean < byte < short < int < long}); 052 * if long operation would cause overflow, return a BigInteger</li> 053 * <li>If either argument is a BigDecimal, coerce both to BigDecimal, operator returns BigDecimal</li> 054 * <li>If either argument is a floating point number, coerce both to Double, operator returns Double</li> 055 * <li>Else treat as BigInteger, perform operation and narrow result to the most precise argument class 056 * </li> 057 * </ol> 058 * 059 * Note that the only exception thrown by JexlArithmetic is and must be ArithmeticException. 060 * 061 * @see JexlOperator 062 * @since 2.0 063 */ 064public class JexlArithmetic { 065 066 /** 067 * Helper interface used when creating an array literal. 068 * 069 * <p>The default implementation creates an array and attempts to type it strictly.</p> 070 * 071 * <ul> 072 * <li>If all objects are of the same type, the array returned will be an array of that same type</li> 073 * <li>If all objects are Numbers, the array returned will be an array of Numbers</li> 074 * <li>If all objects are convertible to a primitive type, the array returned will be an array 075 * of the primitive type</li> 076 * </ul> 077 */ 078 public interface ArrayBuilder { 079 080 /** 081 * Adds a literal to the array. 082 * 083 * @param value The item to add 084 */ 085 void add(Object value); 086 087 /** 088 * Creates the actual "array" instance. 089 * 090 * @param extended true when the last argument is ', ...' 091 * @return The array 092 */ 093 Object create(boolean extended); 094 } 095 096 /** Marker class for coercion operand exceptions. */ 097 public static class CoercionException extends ArithmeticException { 098 private static final long serialVersionUID = 202402081150L; 099 100 /** 101 * Constructs a new instance. 102 * 103 * @param msg The detail message. 104 */ 105 public CoercionException(final String msg) { 106 super(msg); 107 } 108 109 /** 110 * Constructs a new instance. 111 * 112 * @param msg The detail message. 113 * @param cause The cause of this Throwable. 114 * @since 3.5.0 115 */ 116 public CoercionException(final String msg, final Throwable cause) { 117 super(msg); 118 initCause(cause); 119 } 120 } 121 122 /** 123 * Helper interface used when creating a map literal. 124 * <p>The default implementation creates a java.util.HashMap.</p> 125 */ 126 public interface MapBuilder { 127 128 /** 129 * Creates the actual "map" instance. 130 * 131 * @return The map 132 */ 133 Object create(); 134 135 /** 136 * Adds a new entry to the map. 137 * 138 * @param key The map entry key 139 * @param value The map entry value 140 */ 141 void put(Object key, Object value); 142 } 143 144 /** Marker class for null operand exceptions. */ 145 public static class NullOperand extends ArithmeticException { 146 private static final long serialVersionUID = 4720876194840764770L; 147 148 /** Default constructor */ 149 public NullOperand() { 150 } // satisfy Javadoc 151 } 152 153 /** 154 * Helper interface used when creating a set literal. 155 * <p>The default implementation creates a java.util.HashSet.</p> 156 */ 157 public interface SetBuilder { 158 159 /** 160 * Adds a literal to the set. 161 * 162 * @param value The item to add 163 */ 164 void add(Object value); 165 166 /** 167 * Creates the actual "set" instance. 168 * 169 * @return The set 170 */ 171 Object create(); 172 } 173 174 /** 175 * The interface that uberspects JexlArithmetic classes. 176 * <p>This allows overloaded operator methods discovery.</p> 177 */ 178 public interface Uberspect { 179 180 /** 181 * Gets the most specific method for an operator. 182 * 183 * @param operator The operator 184 * @param args The arguments 185 * @return The most specific method or null if no specific override could be found 186 */ 187 JexlMethod getOperator(JexlOperator operator, Object... args); 188 189 /** 190 * Checks whether this uberspect has overloads for a given operator. 191 * 192 * @param operator The operator to check 193 * @return true if an overload exists, false otherwise 194 */ 195 boolean overloads(JexlOperator operator); 196 } 197 198 /** Double.MAX_VALUE as BigDecimal. */ 199 protected static final BigDecimal BIGD_DOUBLE_MAX_VALUE = BigDecimal.valueOf(Double.MAX_VALUE); 200 201 /** -Double.MAX_VALUE as BigDecimal. */ 202 protected static final BigDecimal BIGD_DOUBLE_MIN_VALUE = BigDecimal.valueOf(-Double.MAX_VALUE); 203 204 /** Long.MAX_VALUE as BigInteger. */ 205 protected static final BigInteger BIGI_LONG_MAX_VALUE = BigInteger.valueOf(Long.MAX_VALUE); 206 207 /** Long.MIN_VALUE as BigInteger. */ 208 protected static final BigInteger BIGI_LONG_MIN_VALUE = BigInteger.valueOf(Long.MIN_VALUE); 209 210 /** Default BigDecimal scale. */ 211 protected static final int BIGD_SCALE = -1; 212 213 /** 214 * The float regular expression pattern. 215 * <p> 216 * The decimal and exponent parts are optional and captured allowing to determine if the number is a real 217 * by checking whether one of these 2 capturing groups is not empty. 218 */ 219 public static final Pattern FLOAT_PATTERN = Pattern.compile("^[+-]?\\d*(\\.\\d*)?([eE][+-]?\\d+)?$"); 220 221 /** Maximum length of a regex pattern string for the {@code =~} operator (JEXL-security f012). */ 222 public static final int REGEX_PATTERN_MAX_LENGTH = 2048; 223 224 /** 225 * Hard upper bound on BigInteger literal digits when no engine precision is configured. 226 * Acts as a parse-time DoS guard independent of any MathContext (JEXL-security f014). 227 */ 228 public static final int MAX_BIGINTEGER_DIGITS = 256; 229 230 /** 231 * Attempts transformation of potential array in an abstract list or leave as is. 232 * <p>An array (as in int[]) is not convenient to call methods so when encountered we turn them into lists</p> 233 * 234 * @param container An array or on object 235 * @return An abstract list wrapping the array instance or the initial argument 236 * @see org.apache.commons.jexl3.internal.introspection.ArrayListWrapper 237 */ 238 private static Object arrayWrap(final Object container) { 239 return container.getClass().isArray() 240 ? new org.apache.commons.jexl3.internal.introspection.ArrayListWrapper(container) 241 : container; 242 } 243 244 private static boolean computeCompare321(final JexlArithmetic arithmetic) { 245 Class<?> arithmeticClass = arithmetic.getClass(); 246 while(arithmeticClass != JexlArithmetic.class) { 247 try { 248 final Method cmp = arithmeticClass.getDeclaredMethod("compare", Object.class, Object.class, String.class); 249 if (cmp.getDeclaringClass() != JexlArithmetic.class) { 250 return true; 251 } 252 } catch (final NoSuchMethodException xany) { 253 arithmeticClass = arithmeticClass.getSuperclass(); 254 } catch (final SecurityException xany) { 255 // ignore 256 break; 257 } 258 } 259 return false; 260 } 261 262 /** 263 * Checks if the product of the arguments overflows a {@code long}. 264 * <p>see java8 Math.multiplyExact 265 * 266 * @param x The first value 267 * @param y The second value 268 * @param r The product 269 * @return true if product fits a long, false if it overflows 270 */ 271 @SuppressWarnings("MagicNumber") 272 protected static boolean isMultiplyExact(final long x, final long y, final long r) { 273 final long ax = Math.abs(x); 274 final long ay = Math.abs(y); 275 // Some bits greater than 2^31 that might cause overflow 276 // Check the result using the divide operator 277 // and check for the special case of Long.MIN_VALUE * -1 278 return !((ax | ay) >>> Integer.SIZE - 1 != 0 279 && (y != 0 && r / y != x 280 || x == Long.MIN_VALUE && y == -1)); 281 } 282 283 /** Whether this JexlArithmetic instance behaves in strict or lenient mode. */ 284 private final boolean strict; 285 286 /** The big decimal math context. */ 287 private final MathContext mathContext; 288 289 /** The big decimal scale. */ 290 private final int mathScale; 291 292 /** The dynamic constructor. */ 293 private final Constructor<? extends JexlArithmetic> ctor; 294 295 /** 296 * Determines if the compare method(Object, Object, String) is overriden in this class or one of its 297 * superclasses. 298 */ 299 private final boolean compare321 = computeCompare321(this); 300 301 /** 302 * Creates a JexlArithmetic. 303 * <p>If you derive your own arithmetic, implement the 304 * other constructor that may be needed when dealing with options. 305 * 306 * @param astrict whether this arithmetic is strict or lenient 307 */ 308 public JexlArithmetic(final boolean astrict) { 309 this(astrict, null, Integer.MIN_VALUE); 310 } 311 312 /** 313 * Creates a JexlArithmetic. 314 * <p>The constructor to define in derived classes. 315 * 316 * @param astrict whether this arithmetic is lenient or strict 317 * @param bigdContext The math context instance to use for +,-,/,*,% operations on big decimals. 318 * @param bigdScale The scale used for big decimals. 319 */ 320 public JexlArithmetic(final boolean astrict, final MathContext bigdContext, final int bigdScale) { 321 this.strict = astrict; 322 this.mathContext = bigdContext == null ? MathContext.DECIMAL128 : bigdContext; 323 this.mathScale = bigdScale == Integer.MIN_VALUE ? BIGD_SCALE : bigdScale; 324 Constructor<? extends JexlArithmetic> actor = null; 325 try { 326 actor = getClass().getConstructor(boolean.class, MathContext.class, int.class); 327 } catch (final Exception xany) { 328 // ignore 329 } 330 this.ctor = actor; 331 } 332 333 /** 334 * Add two values together. 335 * <p> 336 * If any numeric add fails on coercion to the appropriate type, 337 * treat as Strings and do concatenation. 338 * </p> 339 * 340 * @param left left argument 341 * @param right right argument 342 * @return left + right. 343 */ 344 public Object add(final Object left, final Object right) { 345 if (left == null && right == null) { 346 return controlNullNullOperands(JexlOperator.ADD); 347 } 348 final boolean strconcat = strict 349 ? left instanceof String || right instanceof String 350 : left instanceof String && right instanceof String; 351 if (!strconcat) { 352 BigInteger bigIntResult = null; 353 try { 354 final boolean strictCast = isStrict(JexlOperator.ADD); 355 // if both (non-null) args fit as long 356 final Number ln = asLongNumber(strictCast, left); 357 final Number rn = asLongNumber(strictCast, right); 358 if (ln != null && rn != null) { 359 final long x = ln.longValue(); 360 final long y = rn.longValue(); 361 final long result = x + y; 362 // detect overflow, see java8 Math.addExact 363 if (((x ^ result) & (y ^ result)) < 0) { 364 return BigInteger.valueOf(x).add(BigInteger.valueOf(y)); 365 } 366 return narrowLong(left, right, result); 367 } 368 // if either are BigDecimal, use that type 369 if (left instanceof BigDecimal || right instanceof BigDecimal) { 370 final BigDecimal l = toBigDecimal(strictCast, left); 371 final BigDecimal r = toBigDecimal(strictCast, right); 372 return l.add(r, getMathContext()); 373 } 374 // if either are floating point (double or float), use double 375 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { 376 final double l = toDouble(strictCast, left); 377 final double r = toDouble(strictCast, right); 378 return l + r; 379 } 380 // otherwise treat as BigInteger 381 final BigInteger l = toBigInteger(strictCast, left); 382 final BigInteger r = toBigInteger(strictCast, right); 383 bigIntResult = l.add(r); 384 } catch (final ArithmeticException nfe) { 385 // ignore and continue in sequence 386 } 387 // precision check is outside the catch so it is not silently swallowed (f013) 388 if (bigIntResult != null) { 389 return narrowBigInteger(left, right, checkBigIntegerPrecision(bigIntResult)); 390 } 391 } 392 return (left == null ? "" : toString(left)).concat(right == null ? "" : toString(right)); 393 } 394 395 /** 396 * Performs a bitwise and. 397 * 398 * @param left The left operand 399 * @param right The right operator 400 * @return left & right 401 */ 402 public Object and(final Object left, final Object right) { 403 final long l = toLong(left); 404 final long r = toLong(right); 405 return l & r; 406 } 407 408 /** 409 * Creates an array builder. 410 * 411 * @param size The number of elements in the array 412 * @return An array builder instance 413 * @deprecated since 3.3.1 414 */ 415 @Deprecated 416 public ArrayBuilder arrayBuilder(final int size) { 417 return arrayBuilder(size, false); 418 } 419 420 /** 421 * Called by the interpreter when evaluating a literal array. 422 * 423 * @param size The number of elements in the array 424 * @param extended whether the map is extended or not 425 * @return The array builder 426 */ 427 public ArrayBuilder arrayBuilder(final int size, final boolean extended) { 428 return new org.apache.commons.jexl3.internal.ArrayBuilder(size, extended); 429 } 430 431 /** 432 * Checks if value class is a number that can be represented exactly in a long. 433 * <p>For convenience, booleans are converted as 1/0 (true/false).</p> 434 * 435 * @param strict whether null argument is converted as 0 or remains null 436 * @param value argument 437 * @return A non-null value if argument can be represented by a long 438 */ 439 protected Number asLongNumber(final boolean strict, final Object value) { 440 if (value instanceof Long 441 || value instanceof Integer 442 || value instanceof Short 443 || value instanceof Byte) { 444 return (Number) value; 445 } 446 if (value instanceof Boolean) { 447 return (boolean) value ? 1L : 0L; 448 } 449 if (value instanceof AtomicBoolean) { 450 final AtomicBoolean b = (AtomicBoolean) value; 451 return b.get() ? 1L : 0L; 452 } 453 if (value == null && !strict) { 454 return 0L; 455 } 456 return null; 457 } 458 459 /** 460 * Checks if value class is a number that can be represented exactly in a long. 461 * <p>For convenience, booleans are converted as 1/0 (true/false).</p> 462 * 463 * @param value argument 464 * @return A non-null value if argument can be represented by a long 465 */ 466 protected Number asLongNumber(final Object value) { 467 return asLongNumber(strict, value); 468 } 469 470 /** 471 * Use or overload and() instead. 472 * 473 * @param lhs left hand side 474 * @param rhs right hand side 475 * @return lhs & rhs 476 * @see JexlArithmetic#and 477 * @deprecated 3.0 478 */ 479 @Deprecated 480 public final Object bitwiseAnd(final Object lhs, final Object rhs) { 481 return and(lhs, rhs); 482 } 483 484 /** 485 * Use or overload or() instead. 486 * 487 * @param lhs left hand side 488 * @param rhs right hand side 489 * @return lhs | rhs 490 * @see JexlArithmetic#or 491 * @deprecated 3.0 492 */ 493 @Deprecated 494 public final Object bitwiseOr(final Object lhs, final Object rhs) { 495 return or(lhs, rhs); 496 } 497 498 /** 499 * Use or overload xor() instead. 500 * 501 * @param lhs left hand side 502 * @param rhs right hand side 503 * @return lhs ^ rhs 504 * @see JexlArithmetic#xor 505 * @deprecated 3.0 506 */ 507 @Deprecated 508 public final Object bitwiseXor(final Object lhs, final Object rhs) { 509 return xor(lhs, rhs); 510 } 511 512 /** 513 * Checks whether a potential collection contains another. 514 * <p>Made protected to make it easier to override if needed.</p> 515 * 516 * @param collection The container which can be a collection or an array (even of primitive) 517 * @param value The value which can be a collection or an array (even of primitive) or a singleton 518 * @return test result or null if there is no arithmetic solution 519 */ 520 protected Boolean collectionContains(final Object collection, final Object value) { 521 // convert arrays if needed 522 final Object left = arrayWrap(collection); 523 if (left instanceof Collection) { 524 final Object right = arrayWrap(value); 525 if (right instanceof Collection) { 526 return ((Collection<?>) left).containsAll((Collection<?>) right); 527 } 528 return ((Collection<?>) left).contains(value); 529 } 530 return null; 531 } 532 533 /** 534 * Performs a comparison. 535 * 536 * @param left The left operand 537 * @param right The right operator 538 * @param operator The operator 539 * @return -1 if left < right; +1 if left > right; 0 if left == right 540 * @throws ArithmeticException if either left or right is null 541 */ 542 protected int compare(final Object left, final Object right, final JexlOperator operator) { 543 // this is a temporary way of allowing pre-3.3 code that overrode compare() to still call 544 // the user method. This method will merge with doCompare in 3.4 and the compare321 flag will disappear. 545 return compare321 546 ? compare(left, right, operator.toString()) 547 : doCompare(left, right, operator); 548 } 549 550 /** 551 * Any override of this method (pre 3.3) should be modified to match the new signature. 552 * 553 * @param left left operand 554 * @param right right operand 555 * @param symbol The operator symbol 556 * @return -1 if left < right; +1 if left > right; 0 if left == right 557 * {@link JexlArithmetic#compare(Object, Object, JexlOperator)} 558 * @deprecated 3.3 559 */ 560 @Deprecated 561 protected int compare(final Object left, final Object right, final String symbol) { 562 JexlOperator operator; 563 try { 564 operator = JexlOperator.valueOf(symbol); 565 } catch (final IllegalArgumentException xill) { 566 // ignore 567 operator = EQ; 568 } 569 return doCompare(left, right, operator); 570 } 571 572 /** 573 * Performs a bitwise complement. 574 * 575 * @param val The operand 576 * @return ~val 577 */ 578 public Object complement(final Object val) { 579 final boolean strictCast = isStrict(JexlOperator.COMPLEMENT); 580 final long l = toLong(strictCast, val); 581 return ~l; 582 } 583 584 /** 585 * Test if left contains right (right matches/in left). 586 * <p>Beware that this "contains " method arguments order is the opposite of the 587 * "in/matches" operator arguments. 588 * {@code x =~ y} means {@code y contains x} thus {@code contains(x, y)}.</p> 589 * <p>When this method returns null during evaluation, the operator code continues trying to find 590 * one through the uberspect.</p> 591 * 592 * @param container The container 593 * @param value The value 594 * @return test result or null if there is no arithmetic solution 595 */ 596 public Boolean contains(final Object container, final Object value) { 597 if (value == null && container == null) { 598 //if both are null L == R 599 return true; 600 } 601 if (value == null || container == null) { 602 // we know both aren't null, therefore L != R 603 return false; 604 } 605 // use arithmetic / pattern matching ? 606 Pattern pattern = null; 607 if (container instanceof Pattern) { 608 pattern = (Pattern) container; 609 controlRegexLength(pattern.pattern().length()); 610 } else if (container instanceof CharSequence) { 611 final String regex = container.toString(); 612 controlRegexLength(regex.length()); 613 pattern = Pattern.compile(regex); 614 } 615 if (pattern != null) { 616 return pattern.matcher(new InterruptibleCharSequence(value.toString())).matches(); 617 } 618 // try contains on map key 619 if (container instanceof Map<?, ?>) { 620 if (value instanceof Map<?, ?>) { 621 return ((Map<?, ?>) container).keySet().containsAll(((Map<?, ?>) value).keySet()); 622 } 623 return ((Map<?, ?>) container).containsKey(value); 624 } 625 // try contains on collection 626 return collectionContains(container, value); 627 } 628 629 /** 630 * Checks the length of a regex pattern string. 631 * 632 * @param length The length of the regex pattern string 633 * @throws ArithmeticException if the length exceeds {@link #REGEX_PATTERN_MAX_LENGTH} 634 */ 635 private static void controlRegexLength(final int length) { 636 if (length > REGEX_PATTERN_MAX_LENGTH) { 637 throw new ArithmeticException( 638 "regular expression too long: " + length + " > " + REGEX_PATTERN_MAX_LENGTH); 639 } 640 } 641 642 /** 643 * The result of +,/,-,*,% when both operands are null. 644 * 645 * @return Integer(0) if lenient 646 * @throws JexlArithmetic.NullOperand if strict 647 * @deprecated 3.3 648 */ 649 @Deprecated 650 protected Object controlNullNullOperands() { 651 if (isStrict()) { 652 throw new NullOperand(); 653 } 654 return 0; 655 } 656 657 /** 658 * The result of +,/,-,*,% when both operands are null. 659 * 660 * @param operator The actual operator 661 * @return Integer(0) if lenient 662 * @throws JexlArithmetic.NullOperand if strict-cast 663 * @since 3.3 664 */ 665 protected Object controlNullNullOperands(final JexlOperator operator) { 666 if (isStrict(operator)) { 667 throw new NullOperand(); 668 } 669 return 0; 670 } 671 672 /** 673 * Throws an NullOperand exception if arithmetic is strict-cast. 674 * 675 * @throws JexlArithmetic.NullOperand if strict 676 * @deprecated 3.3 677 */ 678 @Deprecated 679 protected void controlNullOperand() { 680 if (isStrict()) { 681 throw new NullOperand(); 682 } 683 } 684 685 /** 686 * Throws an NullOperand exception if arithmetic is strict-cast. 687 * <p>This method is called by the cast methods ({@link #toBoolean(boolean, Object)}, 688 * {@link #toInteger(boolean, Object)}, {@link #toDouble(boolean, Object)}, 689 * {@link #toString(boolean, Object)}, {@link #toBigInteger(boolean, Object)}, 690 * {@link #toBigDecimal(boolean, Object)}) when they encounter a null argument.</p> 691 * 692 * @param strictCast whether strict cast is required 693 * @param defaultValue The default value to return, if not strict 694 * @param <T> The value type 695 * @return The default value is strict is false 696 * @throws JexlArithmetic.NullOperand if strict-cast 697 * @since 3.3 698 */ 699 protected <T> T controlNullOperand(final boolean strictCast, final T defaultValue) { 700 if (strictCast) { 701 throw new NullOperand(); 702 } 703 return defaultValue; 704 } 705 706 /** 707 * The last method called before returning a result from a script execution. 708 * 709 * @param returned The returned value 710 * @return The controlled returned value 711 */ 712 public Object controlReturn(final Object returned) { 713 return returned; 714 } 715 716 /** 717 * Creates a literal range. 718 * <p>The default implementation only accepts integers and longs.</p> 719 * 720 * @param from The included lower bound value (null if none) 721 * @param to The included upper bound value (null if none) 722 * @return The range as an iterable 723 * @throws ArithmeticException as an option if creation fails 724 */ 725 public Iterable<?> createRange(final Object from, final Object to) throws ArithmeticException { 726 final long lfrom = toLong(from); 727 final long lto = toLong(to); 728 if (lfrom >= Integer.MIN_VALUE && lfrom <= Integer.MAX_VALUE 729 && lto >= Integer.MIN_VALUE && lto <= Integer.MAX_VALUE) { 730 return org.apache.commons.jexl3.internal.IntegerRange.create((int) lfrom, (int) lto); 731 } 732 return org.apache.commons.jexl3.internal.LongRange.create(lfrom, lto); 733 } 734 735 /** 736 * Creates a JexlArithmetic instance. 737 * Called by options(...) method when another instance of the same class of arithmetic is required. 738 * 739 * @see #options(org.apache.commons.jexl3.JexlEngine.Options) 740 * @param astrict whether this arithmetic is lenient or strict 741 * @param bigdContext The math context instance to use for +,-,/,*,% operations on big decimals. 742 * @param bigdScale The scale used for big decimals. 743 * @return default is a new JexlArithmetic instance 744 * @since 3.1 745 */ 746 protected JexlArithmetic createWithOptions(final boolean astrict, final MathContext bigdContext, final int bigdScale) { 747 if (ctor != null) { 748 try { 749 return ctor.newInstance(astrict, bigdContext, bigdScale); 750 } catch (IllegalAccessException | IllegalArgumentException 751 | InstantiationException | InvocationTargetException xany) { 752 // it was worth the try 753 } 754 } 755 return new JexlArithmetic(astrict, bigdContext, bigdScale); 756 } 757 758 /** 759 * Decrements argument by 1. 760 * 761 * @param val The argument 762 * @return val - 1 763 */ 764 public Object decrement(final Object val) { 765 return increment(val, -1); 766 } 767 768 /** 769 * Divide the left value by the right. 770 * 771 * @param left left argument 772 * @param right right argument 773 * @return left / right 774 * @throws ArithmeticException if right == 0 775 */ 776 public Object divide(final Object left, final Object right) { 777 if (left == null && right == null) { 778 return controlNullNullOperands(JexlOperator.DIVIDE); 779 } 780 final boolean strictCast = isStrict(JexlOperator.DIVIDE); 781 // if both (non-null) args fit as long 782 final Number ln = asLongNumber(strictCast, left); 783 final Number rn = asLongNumber(strictCast, right); 784 if (ln != null && rn != null) { 785 final long x = ln.longValue(); 786 final long y = rn.longValue(); 787 if (y == 0L) { 788 throw new ArithmeticException("/"); 789 } 790 final long result = x / y; 791 return narrowLong(left, right, result); 792 } 793 // if either are BigDecimal, use that type 794 if (left instanceof BigDecimal || right instanceof BigDecimal) { 795 final BigDecimal l = toBigDecimal(strictCast, left); 796 final BigDecimal r = toBigDecimal(strictCast, right); 797 if (BigDecimal.ZERO.equals(r)) { 798 throw new ArithmeticException("/"); 799 } 800 return l.divide(r, getMathContext()); 801 } 802 // if either are floating point (double or float), use double 803 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { 804 final double l = toDouble(strictCast, left); 805 final double r = toDouble(strictCast, right); 806 if (r == 0.0) { 807 throw new ArithmeticException("/"); 808 } 809 return l / r; 810 } 811 // otherwise treat as BigInteger 812 final BigInteger l = toBigInteger(strictCast, left); 813 final BigInteger r = toBigInteger(strictCast, right); 814 if (BigInteger.ZERO.equals(r)) { 815 throw new ArithmeticException("/"); 816 } 817 final BigInteger result = l.divide(r); 818 return narrowBigInteger(left, right, result); 819 } 820 821 private int doCompare(final Object left, final Object right, final JexlOperator operator) { 822 final boolean strictCast = isStrict(operator); 823 if (left != null && right != null) { 824 try { 825 if (left instanceof BigDecimal || right instanceof BigDecimal) { 826 final BigDecimal l = toBigDecimal(strictCast, left); 827 final BigDecimal r = toBigDecimal(strictCast, right); 828 return l.compareTo(r); 829 } 830 if (left instanceof BigInteger || right instanceof BigInteger) { 831 final BigInteger l = toBigInteger(strictCast, left); 832 final BigInteger r = toBigInteger(strictCast, right); 833 return l.compareTo(r); 834 } 835 if (isFloatingPoint(left) || isFloatingPoint(right)) { 836 final double lhs = toDouble(strictCast, left); 837 final double rhs = toDouble(strictCast, right); 838 if (Double.isNaN(lhs)) { 839 if (Double.isNaN(rhs)) { 840 return 0; 841 } 842 return -1; 843 } 844 if (Double.isNaN(rhs)) { 845 // lhs is not NaN 846 return +1; 847 } 848 return Double.compare(lhs, rhs); 849 } 850 if (isNumberable(left) || isNumberable(right)) { 851 final long lhs = toLong(strictCast, left); 852 final long rhs = toLong(strictCast, right); 853 return Long.compare(lhs, rhs); 854 } 855 if (left instanceof String || right instanceof String) { 856 return toString(left).compareTo(toString(right)); 857 } 858 } catch (final CoercionException ignore) { 859 // ignore it, continue in sequence 860 } 861 if (EQ == operator) { 862 return left.equals(right) ? 0 : -1; 863 } 864 if (left instanceof Comparable<?>) { 865 @SuppressWarnings("unchecked") // OK because of instanceof check above 866 final Comparable<Object> comparable = (Comparable<Object>) left; 867 try { 868 return comparable.compareTo(right); 869 } catch (final ClassCastException castException) { 870 // ignore it, continue in sequence 871 } 872 } 873 if (right instanceof Comparable<?>) { 874 @SuppressWarnings("unchecked") // OK because of instanceof check above 875 final Comparable<Object> comparable = (Comparable<Object>) right; 876 try { 877 return -Integer.signum(comparable.compareTo(left)); 878 } catch (final ClassCastException castException) { 879 // ignore it, continue in sequence 880 } 881 } 882 } 883 throw new ArithmeticException("Object comparison:(" + left + 884 " " + operator.getOperatorSymbol() 885 + " " + right + ")"); 886 } 887 888 /** 889 * Check for emptiness of various types: Number, Collection, Array, Map, String. 890 * <p>Override or overload this method to add new signatures to the size operators. 891 * 892 * @param object The object to check the emptiness of 893 * @return The boolean or false if object is not null 894 * @since 3.2 895 */ 896 public Boolean empty(final Object object) { 897 return object == null || isEmpty(object, false); 898 } 899 900 /** 901 * Test if left ends with right. 902 * 903 * @param left left argument 904 * @param right right argument 905 * @return left $= right if there is no arithmetic solution 906 */ 907 public Boolean endsWith(final Object left, final Object right) { 908 if (left == null && right == null) { 909 //if both are null L == R 910 return true; 911 } 912 if (left == null || right == null) { 913 // we know both aren't null, therefore L != R 914 return false; 915 } 916 if (left instanceof CharSequence) { 917 return toString(left).endsWith(toString(right)); 918 } 919 return null; 920 } 921 922 /** 923 * Test if left and right are equal. 924 * 925 * @param left left argument 926 * @param right right argument 927 * @return The test result 928 */ 929 public boolean equals(final Object left, final Object right) { 930 if (left == right) { 931 return true; 932 } 933 if (left == null || right == null) { 934 return false; 935 } 936 final boolean strictCast = isStrict(EQ); 937 if (left instanceof Boolean || right instanceof Boolean) { 938 return toBoolean(left) == toBoolean(strictCast, right); 939 } 940 return compare(left, right, EQ) == 0; 941 } 942 943 /** 944 * Guards a BigInteger result against exceeding the arithmetic context's precision (JEXL-security f013). 945 * <p>When {@link MathContext#getPrecision()} is zero (unlimited), no limit is enforced. 946 * Otherwise, the BigInteger must fit within approximately that many significant decimal digits.</p> 947 * 948 * @param big the value to check 949 * @return big unchanged if within the limit 950 * @throws ArithmeticException when the limit is exceeded 951 */ 952 protected BigInteger checkBigIntegerPrecision(final BigInteger big) { 953 final long precision = getMathContext().getPrecision(); 954 if (precision > 0) { 955 // precision 0 means unlimited; otherwise, one decimal digit ≈ log2(10) ≈ 10/3 bits 956 final long maxBits = precision * 10 / 3 + 1; 957 if (big.bitLength() > maxBits) { 958 throw new ArithmeticException( 959 "BigInteger precision exceeded: " + big.bitLength() + " bits for " + precision + "-digit context"); 960 } 961 } 962 return big; 963 } 964 965 /** 966 * The MathContext instance used for +,-,/,*,% operations on big decimals. 967 * 968 * @return The math context 969 */ 970 public MathContext getMathContext() { 971 return mathContext; 972 } 973 974 /** 975 * The BigDecimal scale used for comparison and coercion operations. 976 * 977 * @return The scale 978 */ 979 public int getMathScale() { 980 return mathScale; 981 } 982 983 /** 984 * Test if left > right. 985 * 986 * @param left left argument 987 * @param right right argument 988 * @return The test result 989 */ 990 public boolean greaterThan(final Object left, final Object right) { 991 if (left == right || left == null || right == null) { 992 return false; 993 } 994 return compare(left, right, JexlOperator.GT) > 0; 995 } 996 997 /** 998 * Test if left >= right. 999 * 1000 * @param left left argument 1001 * @param right right argument 1002 * @return The test result 1003 */ 1004 public boolean greaterThanOrEqual(final Object left, final Object right) { 1005 if (left == right) { 1006 return true; 1007 } 1008 if (left == null || right == null) { 1009 return false; 1010 } 1011 return compare(left, right, JexlOperator.GTE) >= 0; 1012 } 1013 1014 /** 1015 * Increments argument by 1. 1016 * 1017 * @param val The argument 1018 * @return val + 1 1019 */ 1020 public Object increment(final Object val) { 1021 return increment(val, 1); 1022 } 1023 1024 /** 1025 * Add value to number argument. 1026 * 1027 * @param val The number 1028 * @param incr The value to add 1029 * @return val + incr 1030 */ 1031 protected Object increment(final Object val, final int incr) { 1032 if (val == null) { 1033 return incr; 1034 } 1035 if (val instanceof Integer) { 1036 return (Integer) val + incr; 1037 } 1038 if (val instanceof Double) { 1039 return (Double) val + incr; 1040 } 1041 if (val instanceof Long) { 1042 return (Long) val + incr; 1043 } 1044 if (val instanceof BigDecimal) { 1045 final BigDecimal bd = (BigDecimal) val; 1046 return bd.add(BigDecimal.valueOf(incr), this.mathContext); 1047 } 1048 if (val instanceof BigInteger) { 1049 final BigInteger bi = (BigInteger) val; 1050 return bi.add(BigInteger.valueOf(incr)); 1051 } 1052 if (val instanceof Float) { 1053 return (Float) val + incr; 1054 } 1055 if (val instanceof Short) { 1056 return (short) ((Short) val + incr); 1057 } 1058 if (val instanceof Byte) { 1059 return (byte) ((Byte) val + incr); 1060 } 1061 throw new ArithmeticException("Object "+(incr < 0? "decrement":"increment")+":(" + val + ")"); 1062 } 1063 1064 /** 1065 * Evaluates a supplier argument, eventually catching and logging any JexlException. 1066 * 1067 * <p>Used primarily by {@link #empty(Object)} and {@link #size(Object)} to guard argument evaluation. 1068 * If evaluation succeeds, returns the supplier's result. If a {@link JexlException} occurs, logs a 1069 * warning and returns {@link JexlEngine#TRY_FAILED} as an exception-occurred sentinel to the caller.</p> 1070 * 1071 * <p>This method is public to allow overriding.</p> 1072 * 1073 * @param logger The logger for warning messages; may be null 1074 * @param arg The supplier providing the argument to evaluate 1075 * @return The evaluated result on success or {@link JexlEngine#TRY_FAILED} on failure 1076 * @since 3.6.3 1077 */ 1078 public Object evaluate(final Log logger, final Supplier<Object> arg) { 1079 try { 1080 return arg.get(); 1081 } catch (final JexlException e) { 1082 if (logger != null && logger.isWarnEnabled()) { 1083 final String em = e.getMessage(); 1084 final Throwable t = e.getCause(); 1085 if (t == null) { 1086 logger.warn(em, e.clean()); 1087 } else { 1088 final String tm = t.getMessage(); 1089 final String warning = em != null ? tm != null ? em + ", " + tm : em : tm; 1090 logger.warn(warning, JexlException.clean(t)); 1091 } 1092 } 1093 } 1094 return JexlEngine.TRY_FAILED; 1095 } 1096 1097 /** 1098 * Check for emptiness of various types: Number, Collection, Array, Map, String. 1099 * 1100 * @param object The object to check the emptiness of 1101 * @return The boolean or null if there is no arithmetic solution 1102 */ 1103 public Boolean isEmpty(final Object object) { 1104 return isEmpty(object, object == null); 1105 } 1106 1107 /** 1108 * Check for emptiness of various types: Number, Collection, Array, Map, String. 1109 * 1110 * @param object The object to check the emptiness of 1111 * @param def The default value if object emptiness cannot be determined 1112 * @return The boolean or null if there is no arithmetic solution 1113 */ 1114 public Boolean isEmpty(final Object object, final Boolean def) { 1115 if (object != null) { 1116 if (object instanceof Number) { 1117 final double d = ((Number) object).doubleValue(); 1118 return Double.isNaN(d) || d == 0.d; 1119 } 1120 if (object instanceof CharSequence) { 1121 return ((CharSequence) object).length() == 0; 1122 } 1123 if (object.getClass().isArray()) { 1124 return Array.getLength(object) == 0; 1125 } 1126 if (object instanceof Collection<?>) { 1127 return ((Collection<?>) object).isEmpty(); 1128 } 1129 // Map isn't a collection 1130 if (object instanceof Map<?, ?>) { 1131 return ((Map<?, ?>) object).isEmpty(); 1132 } 1133 } 1134 return def; 1135 } 1136 1137 /** 1138 * Is Object a floating point number. 1139 * 1140 * @param o Object to be analyzed. 1141 * @return true if it is a Float or a Double. 1142 */ 1143 protected boolean isFloatingPoint(final Object o) { 1144 return o instanceof Float || o instanceof Double; 1145 } 1146 1147 /** 1148 * Test if the passed value is a floating point number, i.e. a float, double 1149 * or string with ( "." | "E" | "e"). 1150 * 1151 * @param val The object to be tested 1152 * @return true if it is, false otherwise. 1153 */ 1154 protected boolean isFloatingPointNumber(final Object val) { 1155 if (val instanceof Float || val instanceof Double) { 1156 return true; 1157 } 1158 if (val instanceof CharSequence) { 1159 final Matcher m = FLOAT_PATTERN.matcher((CharSequence) val); 1160 // first matcher group is decimal, second is exponent 1161 // one of them must exist hence start({1,2}) >= 0 1162 return m.matches() && (m.start(1) >= 0 || m.start(2) >= 0); 1163 } 1164 return false; 1165 } 1166 1167 /** 1168 * Tests whether negate called with a given argument will always return the same result. 1169 * <p>This is used to determine whether negate results on number literals can be cached. 1170 * If the result on calling negate with the same constant argument may change between calls, 1171 * which means the function is not deterministic, this method must return false. 1172 * 1173 * @return true if negate is idempotent, false otherwise 1174 */ 1175 public boolean isNegateStable() { 1176 return true; 1177 } 1178 1179 /** 1180 * Checks if an operand is considered null. 1181 * 1182 * @param value The operand 1183 * @return true if operand is considered null 1184 */ 1185 protected boolean isNullOperand(final Object value) { 1186 return value == null; 1187 } 1188 1189 /** 1190 * Is Object a whole number. 1191 * 1192 * @param o Object to be analyzed. 1193 * @return true if Integer, Long, Byte, Short or Character. 1194 */ 1195 protected boolean isNumberable(final Object o) { 1196 return o instanceof Integer 1197 || o instanceof Long 1198 || o instanceof Byte 1199 || o instanceof Short 1200 || o instanceof Character; 1201 } 1202 1203 /** 1204 * Tests whether positivize called with a given argument will always return the same result. 1205 * <p>This is used to determine whether positivize results on number literals can be cached. 1206 * If the result on calling positivize with the same constant argument may change between calls, 1207 * which means the function is not deterministic, this method must return false. 1208 * 1209 * @return true if positivize is idempotent, false otherwise 1210 */ 1211 public boolean isPositivizeStable() { 1212 return true; 1213 } 1214 1215 /** 1216 * Checks whether this JexlArithmetic instance 1217 * strictly considers null as an error when used as operand unexpectedly. 1218 * 1219 * @return true if strict, false if lenient 1220 */ 1221 public boolean isStrict() { 1222 return strict; 1223 } 1224 1225 /** 1226 * Tests whether this arithmetic considers a given operator as strict or null-safe. 1227 * <p>When an operator is strict, it does <em>not</em> accept null arguments when the arithmetic is strict. 1228 * If null-safe (ie not-strict), the operator does accept null arguments even if the arithmetic itself is strict.</p> 1229 * <p>The default implementation considers equal/not-equal operators as null-safe so one can check for null as in 1230 * <code>if (myvar == null) {...}</code>. Note that this operator is used for equal and not-equal syntax. The complete 1231 * list of operators that are not strict are (==, [], []=, ., .=, empty, size, contains).</p> 1232 * <p>An arithmetic refining its strict behavior handling for more operators must declare which by overriding 1233 * this method.</p> 1234 * 1235 * @param operator The operator to check for null-argument(s) handling 1236 * @return true if operator considers null arguments as errors, false if operator has appropriate semantics 1237 * for null argument(s) 1238 */ 1239 public boolean isStrict(final JexlOperator operator) { 1240 if (operator != null) { 1241 switch (operator) { 1242 case EQ: 1243 case EQSTRICT: 1244 case ARRAY_GET: 1245 case ARRAY_SET: 1246 case PROPERTY_GET: 1247 case PROPERTY_SET: 1248 case EMPTY: 1249 case SIZE: 1250 case CONTAINS: 1251 return false; 1252 default: 1253 return isStrict(); 1254 } 1255 } 1256 return isStrict(); 1257 } 1258 1259 /** 1260 * Tests if left < right. 1261 * 1262 * @param left left argument 1263 * @param right right argument 1264 * @return The test result 1265 */ 1266 public boolean lessThan(final Object left, final Object right) { 1267 if (left == right || left == null || right == null) { 1268 return false; 1269 } 1270 return compare(left, right, JexlOperator.LT) < 0; 1271 1272 } 1273 1274 /** 1275 * Tests if left <= right. 1276 * 1277 * @param left left argument 1278 * @param right right argument 1279 * @return The test result 1280 */ 1281 public boolean lessThanOrEqual(final Object left, final Object right) { 1282 if (left == right) { 1283 return true; 1284 } 1285 if (left == null || right == null) { 1286 return false; 1287 } 1288 return compare(left, right, JexlOperator.LTE) <= 0; 1289 } 1290 1291 /** 1292 * Use or overload not() instead. 1293 * 1294 * @param arg argument 1295 * @return !arg 1296 * @see JexlArithmetic#not 1297 * @deprecated 3.0 1298 */ 1299 @Deprecated 1300 public final Object logicalNot(final Object arg) { 1301 return not(arg); 1302 } 1303 1304 /** 1305 * Creates a map-builder. 1306 * 1307 * @param size The number of elements in the map 1308 * @return A map-builder instance 1309 * @deprecated 3.3 1310 */ 1311 @Deprecated 1312 public MapBuilder mapBuilder(final int size) { 1313 return mapBuilder(size, false); 1314 } 1315 1316 /** 1317 * Called by the interpreter when evaluating a literal map. 1318 * 1319 * @param size The number of elements in the map 1320 * @param extended whether the map is extended or not 1321 * @return The map builder 1322 */ 1323 public MapBuilder mapBuilder(final int size, final boolean extended) { 1324 return new org.apache.commons.jexl3.internal.MapBuilder(size, extended); 1325 } 1326 1327 /** 1328 * Use or overload contains() instead. 1329 * 1330 * @param lhs left hand side 1331 * @param rhs right hand side 1332 * @return contains(rhs, lhs) 1333 * @see JexlArithmetic#contains 1334 * @deprecated 3.0 1335 */ 1336 @Deprecated 1337 public final Object matches(final Object lhs, final Object rhs) { 1338 return contains(rhs, lhs); 1339 } 1340 1341 /** 1342 * left value modulo right. 1343 * 1344 * @param left left argument 1345 * @param right right argument 1346 * @return left % right 1347 * @throws ArithmeticException if right == 0.0 1348 */ 1349 public Object mod(final Object left, final Object right) { 1350 if (left == null && right == null) { 1351 return controlNullNullOperands(JexlOperator.MOD); 1352 } 1353 final boolean strictCast = isStrict(JexlOperator.MOD); 1354 // if both (non-null) args fit as long 1355 final Number ln = asLongNumber(strictCast, left); 1356 final Number rn = asLongNumber(strictCast, right); 1357 if (ln != null && rn != null) { 1358 final long x = ln.longValue(); 1359 final long y = rn.longValue(); 1360 if (y == 0L) { 1361 throw new ArithmeticException("%"); 1362 } 1363 final long result = x % y; 1364 return narrowLong(left, right, result); 1365 } 1366 // if either are BigDecimal, use that type 1367 if (left instanceof BigDecimal || right instanceof BigDecimal) { 1368 final BigDecimal l = toBigDecimal(strictCast, left); 1369 final BigDecimal r = toBigDecimal(strictCast, right); 1370 if (BigDecimal.ZERO.equals(r)) { 1371 throw new ArithmeticException("%"); 1372 } 1373 return l.remainder(r, getMathContext()); 1374 } 1375 // if either are floating point (double or float), use double 1376 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { 1377 final double l = toDouble(strictCast, left); 1378 final double r = toDouble(strictCast, right); 1379 if (r == 0.0) { 1380 throw new ArithmeticException("%"); 1381 } 1382 return l % r; 1383 } 1384 // otherwise treat as BigInteger 1385 final BigInteger l = toBigInteger(strictCast, left); 1386 final BigInteger r = toBigInteger(strictCast, right); 1387 if (BigInteger.ZERO.equals(r)) { 1388 throw new ArithmeticException("%"); 1389 } 1390 final BigInteger result = l.mod(r); 1391 return narrowBigInteger(left, right, result); 1392 } 1393 1394 /** 1395 * Multiply the left value by the right. 1396 * 1397 * @param left left argument 1398 * @param right right argument 1399 * @return left * right. 1400 */ 1401 public Object multiply(final Object left, final Object right) { 1402 if (left == null && right == null) { 1403 return controlNullNullOperands(JexlOperator.MULTIPLY); 1404 } 1405 final boolean strictCast = isStrict(JexlOperator.MULTIPLY); 1406 // if both (non-null) args fit as long 1407 final Number ln = asLongNumber(strictCast, left); 1408 final Number rn = asLongNumber(strictCast, right); 1409 if (ln != null && rn != null) { 1410 final long x = ln.longValue(); 1411 final long y = rn.longValue(); 1412 final long result = x * y; 1413 // detect overflow 1414 if (!isMultiplyExact(x, y, result)) { 1415 return BigInteger.valueOf(x).multiply(BigInteger.valueOf(y)); 1416 } 1417 return narrowLong(left, right, result); 1418 } 1419 // if either are BigDecimal, use that type 1420 if (left instanceof BigDecimal || right instanceof BigDecimal) { 1421 final BigDecimal l = toBigDecimal(strictCast, left); 1422 final BigDecimal r = toBigDecimal(strictCast, right); 1423 return l.multiply(r, getMathContext()); 1424 } 1425 // if either are floating point (double or float), use double 1426 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { 1427 final double l = toDouble(strictCast, left); 1428 final double r = toDouble(strictCast, right); 1429 return l * r; 1430 } 1431 // otherwise treat as BigInteger; pre-check bit-length sum to avoid O(n²) on huge operands 1432 final BigInteger l = toBigInteger(strictCast, left); 1433 final BigInteger r = toBigInteger(strictCast, right); 1434 final long precision = getMathContext().getPrecision(); 1435 final int lBitLength = l.bitLength(); 1436 final int rBitLength = r.bitLength(); 1437 final long bitLengthLimit = precision * 10 / 3 + 1; 1438 if (precision > 0 && lBitLength + rBitLength > bitLengthLimit) { 1439 throw new ArithmeticException("BigInteger precision exceeded: limit=" + bitLengthLimit 1440 + ", leftBitLength=" + lBitLength 1441 + ", rightBitLength=" + rBitLength 1442 + ", contextPrecision=" + precision); 1443 } 1444 final BigInteger result = l.multiply(r); 1445 return narrowBigInteger(left, right, result); 1446 } 1447 1448 /** 1449 * Narrows a double to a float if there is no information loss. 1450 * 1451 * @param value The double value 1452 * @param narrow The target narrow class 1453 * @return The narrowed or initial number 1454 */ 1455 private Number narrow(final Class<?> narrow, final double value) { 1456 return narrowAccept(narrow, Float.class) && (float) value == value 1457 ? (float) value 1458 : value; 1459 } 1460 1461 /** 1462 * Given a Number, return the value using the smallest type the result 1463 * will fit into. 1464 * <p>This works hand in hand with parameter 'widening' in Java 1465 * method calls, e.g. a call to substring(int, int) with an int and a long 1466 * will fail, but a call to substring(int, int) with an int and a short will 1467 * succeed.</p> 1468 * 1469 * @param original The original number. 1470 * @return A value of the smallest type the original number will fit into. 1471 */ 1472 public Number narrow(final Number original) { 1473 return narrowNumber(original, null); 1474 } 1475 1476 /** 1477 * Tests whether we consider the narrow class as a potential candidate for narrowing the source. 1478 * 1479 * @param narrow The target narrow class 1480 * @param source The original source class 1481 * @return true if attempt to narrow source to target is accepted 1482 */ 1483 protected boolean narrowAccept(final Class<?> narrow, final Class<?> source) { 1484 return narrow == null || narrow.equals(source); 1485 } 1486 1487 /** 1488 * Replace all numbers in an arguments array with the smallest type that will fit. 1489 * 1490 * @param args The argument array 1491 * @return true if some arguments were narrowed and args array is modified, 1492 * false if no narrowing occurred and args array has not been modified 1493 */ 1494 public boolean narrowArguments(final Object[] args) { 1495 boolean narrowed = false; 1496 if (args != null) { 1497 for (int a = 0; a < args.length; ++a) { 1498 final Object arg = args[a]; 1499 if (arg instanceof Number) { 1500 final Number narg = (Number) arg; 1501 final Number narrow = narrow(narg); 1502 if (!narg.equals(narrow)) { 1503 args[a] = narrow; 1504 narrowed = true; 1505 } 1506 } 1507 } 1508 } 1509 return narrowed; 1510 } 1511 1512 /** 1513 * Given a BigDecimal, attempt to narrow it to an Integer or Long if it fits and 1514 * one of the arguments is numberable. 1515 * 1516 * @param lhs The left-hand side operand that lead to the bigd result 1517 * @param rhs The right-hand side operand that lead to the bigd result 1518 * @param big The BigDecimal to narrow 1519 * @return An Integer or Long if narrowing is possible, the original BigDecimal otherwise 1520 */ 1521 protected Number narrowBigDecimal(final Object lhs, final Object rhs, final BigDecimal big) { 1522 return narrowToLong(lhs, rhs, big, BigDecimal::longValueExact); 1523 } 1524 1525 /** 1526 * Given a BigInteger, narrow it to an Integer or Long if it fits and the arguments 1527 * class allow it. 1528 * <p> 1529 * The rules are: 1530 * if either arguments is a BigInteger, no narrowing will occur 1531 * if either arguments is a Long, no narrowing to Integer will occur 1532 * </p> 1533 * 1534 * @param lhs The left-hand side operand that lead to the bigi result 1535 * @param rhs The right-hand side operand that lead to the bigi result 1536 * @param big The BigInteger to narrow 1537 * @return An Integer or Long if narrowing is possible, the original BigInteger otherwise 1538 */ 1539 protected Number narrowBigInteger(final Object lhs, final Object rhs, final BigInteger big) { 1540 return narrowToLong(lhs, rhs, big, BigInteger::longValueExact); 1541 } 1542 1543 /** 1544 * Given a generic number, attempt to narrow it to an Integer or Long if it fits and 1545 * one of the arguments is numberable. 1546 * 1547 * @param lhs The left-hand side operand that lead to the big result 1548 * @param rhs The right-hand side operand that lead to the big result 1549 * @param big The number to narrow 1550 * @param toLongFunction The function to convert the number to a long 1551 * @param <X> The number type 1552 * @return An Integer or Long if narrowing is possible, the original number otherwise 1553 */ 1554 protected <X extends Number> Number narrowToLong(final Object lhs, final Object rhs, final X big, final ToLongFunction<X> toLongFunction) { 1555 if (isNumberable(lhs) || isNumberable(rhs)) { 1556 try { 1557 final long l = toLongFunction.applyAsLong(big); 1558 // coerce to int when possible (int being so often used in method parms) 1559 if ((int) l == l) { 1560 return (int) l; 1561 } 1562 return l; 1563 } catch (final ArithmeticException xa) { 1564 // ignore, no exact value possible 1565 } 1566 } 1567 return big; 1568 } 1569 1570 /** 1571 * Given a long, attempt to narrow it to an int. 1572 * <p>Narrowing will only occur if no operand is a Long. 1573 * 1574 * @param lhs The left hand side operand that lead to the long result 1575 * @param rhs The right hand side operand that lead to the long result 1576 * @param r The long to narrow 1577 * @return An Integer if narrowing is possible, the original Long otherwise 1578 */ 1579 protected Number narrowLong(final Object lhs, final Object rhs, final long r) { 1580 if (!(lhs instanceof Long || rhs instanceof Long) && (int) r == r) { 1581 return (int) r; 1582 } 1583 return r; 1584 } 1585 1586 /** 1587 * Given a Number, return the value attempting to narrow it to a target class. 1588 * 1589 * @param original The original number 1590 * @param narrow The attempted target class 1591 * @return The narrowed number or the source if no narrowing was possible 1592 */ 1593 public Number narrowNumber(final Number original, final Class<?> narrow) { 1594 if (original != null) { 1595 final long value; 1596 if (original instanceof BigDecimal) { 1597 final BigDecimal big = (BigDecimal) original; 1598 try { 1599 // can it be represented as a long? 1600 value = big.longValueExact(); 1601 // continue in sequence to try and further reduce 1602 } catch (final ArithmeticException xa) { 1603 // if it is bigger than a double, it cannot be narrowed 1604 if (big.compareTo(BIGD_DOUBLE_MAX_VALUE) > 0 1605 || big.compareTo(BIGD_DOUBLE_MIN_VALUE) < 0) { 1606 return original; 1607 } 1608 // represent as double 1609 return narrow(narrow, original.doubleValue()); 1610 } 1611 // this continues with value as long 1612 } else { 1613 if (isFloatingPoint(original)) { 1614 final double doubleValue = original.doubleValue(); 1615 // if it is not equivalent to a Long... 1616 if ((long) doubleValue != doubleValue) { 1617 return narrow(narrow, doubleValue); 1618 } 1619 // else it can be represented as a long 1620 } else if (original instanceof BigInteger) { 1621 final BigInteger bigi = (BigInteger) original; 1622 // if it is bigger than a Long, it cannot be narrowed 1623 if (!BigInteger.valueOf(bigi.longValue()).equals(bigi)) { 1624 return original; 1625 } 1626 // else it can be represented as a long 1627 } 1628 value = original.longValue(); 1629 } 1630 // it can be represented as a long; determine the smallest possible numberable representation 1631 if (narrowAccept(narrow, Byte.class) && (byte) value == value) { 1632 // it will fit in a byte 1633 return (byte) value; 1634 } 1635 if (narrowAccept(narrow, Short.class) && (short) value == value) { 1636 return (short) value; 1637 } 1638 if (narrowAccept(narrow, Integer.class) && (int) value == value) { 1639 return (int) value; 1640 } 1641 } 1642 return original; 1643 } 1644 1645 /** 1646 * Negates a value (unary minus for numbers). 1647 * 1648 * @see #isNegateStable() 1649 * @param val The value to negate 1650 * @return The negated value 1651 */ 1652 public Object negate(final Object val) { 1653 if (val == null) { 1654 return null; 1655 } 1656 if (val instanceof Integer) { 1657 return -((Integer) val); 1658 } 1659 if (val instanceof Double) { 1660 return - ((Double) val); 1661 } 1662 if (val instanceof Long) { 1663 return -((Long) val); 1664 } 1665 if (val instanceof BigDecimal) { 1666 return ((BigDecimal) val).negate(); 1667 } 1668 if (val instanceof BigInteger) { 1669 return ((BigInteger) val).negate(); 1670 } 1671 if (val instanceof Float) { 1672 return -((Float) val); 1673 } 1674 if (val instanceof Short) { 1675 return (short) -((Short) val); 1676 } 1677 if (val instanceof Byte) { 1678 return (byte) -((Byte) val); 1679 } 1680 if (val instanceof Boolean) { 1681 return !(Boolean) val; 1682 } 1683 if (val instanceof AtomicBoolean) { 1684 return !((AtomicBoolean) val).get(); 1685 } 1686 throw new ArithmeticException("Object negate:(" + val + ")"); 1687 } 1688 1689 /** 1690 * Performs a logical not. 1691 * 1692 * @param val The operand 1693 * @return !val 1694 */ 1695 public Object not(final Object val) { 1696 final boolean strictCast = isStrict(JexlOperator.NOT); 1697 return !toBoolean(strictCast, val); 1698 } 1699 1700 /** 1701 * Apply options to this arithmetic which eventually may create another instance. 1702 * 1703 * @see #createWithOptions(boolean, java.math.MathContext, int) 1704 * @param context The context that may extend {@link JexlContext.OptionsHandle} to use 1705 * @return A new arithmetic instance or this 1706 * @since 3.1 1707 */ 1708 public JexlArithmetic options(final JexlContext context) { 1709 if (context instanceof JexlContext.OptionsHandle) { 1710 return options(((JexlContext.OptionsHandle) context).getEngineOptions()); 1711 } 1712 if (context instanceof JexlEngine.Options) { 1713 return options((JexlEngine.Options) context); 1714 } 1715 return this; 1716 } 1717 1718 /** 1719 * Apply options to this arithmetic which eventually may create another instance. 1720 * 1721 * @see #createWithOptions(boolean, java.math.MathContext, int) 1722 * @param options The {@link JexlEngine.Options} to use 1723 * @return An arithmetic with those options set 1724 * @deprecated 3.2 1725 */ 1726 @Deprecated 1727 public JexlArithmetic options(final JexlEngine.Options options) { 1728 if (options != null) { 1729 final boolean strict = Boolean.TRUE.equals(options.isStrictArithmetic()) || isStrict(); 1730 MathContext bigdContext = options.getArithmeticMathContext(); 1731 if (bigdContext == null) { 1732 bigdContext = getMathContext(); 1733 } 1734 int bigdScale = options.getArithmeticMathScale(); 1735 if (bigdScale == Integer.MIN_VALUE) { 1736 bigdScale = getMathScale(); 1737 } 1738 if (strict != isStrict() 1739 || bigdScale != getMathScale() 1740 || bigdContext != getMathContext()) { 1741 return createWithOptions(strict, bigdContext, bigdScale); 1742 } 1743 } 1744 return this; 1745 } 1746 1747 /** 1748 * Apply options to this arithmetic which eventually may create another instance. 1749 * 1750 * @see #createWithOptions(boolean, java.math.MathContext, int) 1751 * @param options The {@link JexlEngine.Options} to use 1752 * @return An arithmetic with those options set 1753 */ 1754 public JexlArithmetic options(final JexlOptions options) { 1755 if (options != null) { 1756 final boolean ostrict = options.isStrictArithmetic(); 1757 MathContext bigdContext = options.getMathContext(); 1758 if (bigdContext == null) { 1759 bigdContext = getMathContext(); 1760 } 1761 int bigdScale = options.getMathScale(); 1762 if (bigdScale == Integer.MIN_VALUE) { 1763 bigdScale = getMathScale(); 1764 } 1765 if (ostrict != isStrict() 1766 || bigdScale != getMathScale() 1767 || bigdContext != getMathContext()) { 1768 return createWithOptions(ostrict, bigdContext, bigdScale); 1769 } 1770 } 1771 return this; 1772 } 1773 1774 /** 1775 * Performs a bitwise or. 1776 * 1777 * @param left The left operand 1778 * @param right The right operator 1779 * @return left | right 1780 */ 1781 public Object or(final Object left, final Object right) { 1782 final long l = toLong(left); 1783 final long r = toLong(right); 1784 return l | r; 1785 } 1786 1787 /** 1788 * Convert a string to a BigDecimal. 1789 * <>Empty string is considered as 0. 1790 * 1791 * @param arg The arg 1792 * @return A BigDecimal 1793 * @throws CoercionException if the string cannot be coerced into a BigDecimal 1794 */ 1795 private BigDecimal parseBigDecimal(final String arg) throws ArithmeticException { 1796 try { 1797 return arg.isEmpty()? BigDecimal.ZERO : new BigDecimal(arg, getMathContext()); 1798 } catch (final NumberFormatException e) { 1799 throw new CoercionException("BigDecimal coercion: ("+ arg +")", e); 1800 } 1801 } 1802 1803 /** 1804 * Converts a string to a big integer. 1805 * <>Empty string is considered as 0. 1806 * 1807 * @param arg The arg 1808 * @return A big integer 1809 * @throws ArithmeticException if the string cannot be coerced into a big integer 1810 */ 1811 private BigInteger parseBigInteger(final String arg) throws ArithmeticException { 1812 try { 1813 return arg.isEmpty() ? BigInteger.ZERO : checkBigIntegerPrecision(new BigInteger(arg)); 1814 } catch (final NumberFormatException e) { 1815 throw new CoercionException("BigInteger coercion: ("+ arg +")", e); 1816 } 1817 } 1818 1819 /** 1820 * Convert a string to a double. 1821 * <>Empty string is considered as NaN. 1822 * 1823 * @param arg The arg 1824 * @return A double 1825 * @throws ArithmeticException if the string cannot be coerced into a double 1826 */ 1827 private double parseDouble(final String arg) throws ArithmeticException { 1828 try { 1829 return arg.isEmpty()? Double.NaN : Double.parseDouble(arg); 1830 } catch (final NumberFormatException e) { 1831 throw new CoercionException("Double coercion: ("+ arg +")", e); 1832 } 1833 } 1834 1835 /** 1836 * Converts a string to an int. 1837 * <p>This ensures the represented number is a natural (not a real).</p> 1838 * 1839 * @param arg The arg 1840 * @return An int 1841 * @throws ArithmeticException if the string cannot be coerced into a long 1842 */ 1843 private int parseInteger(final String arg) throws ArithmeticException { 1844 final long l = parseLong(arg); 1845 final int i = (int) l; 1846 if (i == l) { 1847 return i; 1848 } 1849 throw new CoercionException("Int coercion: ("+ arg +")"); 1850 } 1851 1852 /** 1853 * Converts a string to a long. 1854 * <p>This ensures the represented number is a natural (not a real).</p> 1855 * 1856 * @param arg The arg 1857 * @return A long 1858 * @throws ArithmeticException if the string cannot be coerced into a long 1859 */ 1860 private long parseLong(final String arg) throws ArithmeticException { 1861 final double d = parseDouble(arg); 1862 if (Double.isNaN(d)) { 1863 return 0L; 1864 } 1865 final double f = floor(d); 1866 if (d == f) { 1867 return (long) d; 1868 } 1869 throw new CoercionException("Long coercion: ("+ arg +")"); 1870 } 1871 1872 /** 1873 * Parse an identifier which must be of the form: 1874 * 0|([1-9][0-9]*) 1875 * 1876 * @param id The identifier 1877 * @return An integer or null 1878 */ 1879 public static Integer parseIdentifier(final Object id) { 1880 if (id instanceof Number) { 1881 return ((Number) id).intValue(); 1882 } 1883 // hand coded because the was no way to fail on leading '0's using NumberFormat 1884 if (id instanceof CharSequence) { 1885 final CharSequence str = (CharSequence) id; 1886 final int length = str.length(); 1887 // cannot be empty string and cannot be longer than Integer.MAX_VALUE representation 1888 if (length > 0 && length <= 10) { 1889 int val = 0; 1890 for (int i = 0; i < length; ++i) { 1891 final char c = str.charAt(i); 1892 // leading 0s but no just 0, numeric only 1893 if (c == '0' && val == 0 && length > 1 || c < '0' || c > '9') { 1894 return null; 1895 } 1896 val *= 10; 1897 val += c - '0'; 1898 } 1899 return val; 1900 } 1901 } 1902 return null; 1903 } 1904 1905 /** 1906 * Positivize value (unary plus for numbers). 1907 * <p>C/C++/C#/Java perform integral promotion of the operand, ie 1908 * cast to int if type can be represented as int without loss of precision. 1909 * 1910 * @see #isPositivizeStable() 1911 * @param val The value to positivize 1912 * @return The positive value 1913 */ 1914 public Object positivize(final Object val) { 1915 if (val == null) { 1916 return null; 1917 } 1918 if (val instanceof Short) { 1919 return ((Short) val).intValue(); 1920 } 1921 if (val instanceof Byte) { 1922 return ((Byte) val).intValue(); 1923 } 1924 if (val instanceof Number) { 1925 return val; 1926 } 1927 if (val instanceof Character) { 1928 return (int) (Character) val; 1929 } 1930 if (val instanceof Boolean) { 1931 return val; 1932 } 1933 if (val instanceof AtomicBoolean) { 1934 return ((AtomicBoolean) val).get(); 1935 } 1936 throw new ArithmeticException("Object positivize:(" + val + ")"); 1937 } 1938 1939 /** 1940 * Ensure a big decimal is rounded by this arithmetic scale and rounding mode. 1941 * 1942 * @param number The big decimal to round 1943 * @return The rounded big decimal 1944 */ 1945 protected BigDecimal roundBigDecimal(final BigDecimal number) { 1946 final int mscale = getMathScale(); 1947 if (mscale >= 0) { 1948 return number.setScale(mscale, getMathContext().getRoundingMode()); 1949 } 1950 return number; 1951 } 1952 1953 /** 1954 * Creates a set-builder. 1955 * 1956 * @param size The number of elements in the set 1957 * @return A set-builder instance 1958 * @deprecated since 3.3.1 1959 */ 1960 @Deprecated 1961 public SetBuilder setBuilder(final int size) { 1962 return setBuilder(size, false); 1963 } 1964 1965 /** 1966 * Called by the interpreter when evaluating a literal set. 1967 * 1968 * @param size The number of elements in the set 1969 * @param extended whether the set is extended or not 1970 * @return The array builder 1971 */ 1972 public SetBuilder setBuilder(final int size, final boolean extended) { 1973 return new org.apache.commons.jexl3.internal.SetBuilder(size, extended); 1974 } 1975 1976 /** 1977 * Shifts a bit pattern to the right. 1978 * 1979 * @param left left argument 1980 * @param right right argument 1981 * @return left << right. 1982 */ 1983 public Object shiftLeft(final Object left, final Object right) { 1984 final long l = toLong(left); 1985 final int r = toInteger(right); 1986 return l << r; 1987 } 1988 1989 /** 1990 * Shifts a bit pattern to the right. 1991 * 1992 * @param left left argument 1993 * @param right right argument 1994 * @return left >> right. 1995 */ 1996 public Object shiftRight(final Object left, final Object right) { 1997 final long l = toLong(left); 1998 final long r = toInteger(right); 1999 return l >> r; 2000 } 2001 2002 /** 2003 * Shifts a bit pattern to the right unsigned. 2004 * 2005 * @param left left argument 2006 * @param right right argument 2007 * @return left >>> right. 2008 */ 2009 public Object shiftRightUnsigned(final Object left, final Object right) { 2010 final long l = toLong(left); 2011 final long r = toInteger(right); 2012 return l >>> r; 2013 } 2014 2015 /** 2016 * Calculate the {@code size} of various types: Collection, Array, Map, String. 2017 * 2018 * @param object The object to get the size of 2019 * @return The <em>size</em> of object, 0 if null, 1 if there is no <em>better</em> solution 2020 */ 2021 public Integer size(final Object object) { 2022 return size(object, object == null ? 0 : 1); 2023 } 2024 2025 /** 2026 * Calculate the {@code size} of various types: Collection, Array, Map, String. 2027 * 2028 * @param object The object to get the size of 2029 * @param def The default value if object size cannot be determined 2030 * @return The size of object or null if there is no arithmetic solution 2031 */ 2032 public Integer size(final Object object, final Integer def) { 2033 if (object instanceof CharSequence) { 2034 return ((CharSequence) object).length(); 2035 } 2036 if (object.getClass().isArray()) { 2037 return Array.getLength(object); 2038 } 2039 if (object instanceof Collection<?>) { 2040 return ((Collection<?>) object).size(); 2041 } 2042 if (object instanceof Map<?, ?>) { 2043 return ((Map<?, ?>) object).size(); 2044 } 2045 return def; 2046 } 2047 2048 /** 2049 * Test if left starts with right. 2050 * 2051 * @param left left argument 2052 * @param right right argument 2053 * @return left ^= right or null if there is no arithmetic solution 2054 */ 2055 public Boolean startsWith(final Object left, final Object right) { 2056 if (left == null && right == null) { 2057 //if both are null L == R 2058 return true; 2059 } 2060 if (left == null || right == null) { 2061 // we know both aren't null, therefore L != R 2062 return false; 2063 } 2064 if (left instanceof CharSequence) { 2065 return toString(left).startsWith(toString(right)); 2066 } 2067 return null; 2068 } 2069 2070 /** 2071 * Test if left and right are strictly equal. 2072 * <p>They must have the same class, comparable and the comparison returns 0.</p> 2073 * 2074 * @param left left argument 2075 * @param right right argument 2076 * @return The test result 2077 */ 2078 public boolean strictEquals(final Object left, final Object right) { 2079 if (left == right) { 2080 return true; 2081 } 2082 if (left == null || right == null) { 2083 return false; 2084 } 2085 if (left.getClass().equals(right.getClass())) { 2086 return left.equals(right); 2087 } 2088 return false; 2089 } 2090 2091 /** 2092 * Subtract the right value from the left. 2093 * 2094 * @param left left argument 2095 * @param right right argument 2096 * @return left - right. 2097 */ 2098 public Object subtract(final Object left, final Object right) { 2099 if (left == null && right == null) { 2100 return controlNullNullOperands(JexlOperator.SUBTRACT); 2101 } 2102 final boolean strictCast = isStrict(JexlOperator.SUBTRACT); 2103 // if both (non-null) args fit as long 2104 final Number ln = asLongNumber(strictCast, left); 2105 final Number rn = asLongNumber(strictCast, right); 2106 if (ln != null && rn != null) { 2107 final long x = ln.longValue(); 2108 final long y = rn.longValue(); 2109 final long result = x - y; 2110 // detect overflow, see java8 Math.subtractExact 2111 if (((x ^ y) & (x ^ result)) < 0) { 2112 return BigInteger.valueOf(x).subtract(BigInteger.valueOf(y)); 2113 } 2114 return narrowLong(left, right, result); 2115 } 2116 // if either are BigDecimal, use that type 2117 if (left instanceof BigDecimal || right instanceof BigDecimal) { 2118 final BigDecimal l = toBigDecimal(strictCast, left); 2119 final BigDecimal r = toBigDecimal(strictCast, right); 2120 return l.subtract(r, getMathContext()); 2121 } 2122 // if either are floating point (double or float), use double 2123 if (isFloatingPointNumber(left) || isFloatingPointNumber(right)) { 2124 final double l = toDouble(strictCast, left); 2125 final double r = toDouble(strictCast, right); 2126 return l - r; 2127 } 2128 // otherwise treat as BigInteger 2129 final BigInteger l = toBigInteger(strictCast, left); 2130 final BigInteger r = toBigInteger(strictCast, right); 2131 final BigInteger result = l.subtract(r); 2132 return narrowBigInteger(left, right, checkBigIntegerPrecision(result)); 2133 } 2134 2135 /** 2136 * Test if a condition is true or false. 2137 * 2138 * @param object The object to use as condition 2139 * @return true or false 2140 * @since 3.3 2141 */ 2142 public boolean testPredicate(final Object object) { 2143 final boolean strictCast = isStrict(JexlOperator.CONDITION); 2144 return toBoolean(strictCast, object); 2145 } 2146 2147 /** 2148 * Coerce to a BigDecimal. 2149 * <p>Double.NaN, null and empty string coerce to zero.</p> 2150 * <p>Boolean false is 0, true is 1.</p> 2151 * 2152 * @param strict true if the calling operator or casting is strict, false otherwise 2153 * @param val The object to be coerced. 2154 * @return A BigDecimal. 2155 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2156 * @since 3.3 2157 */ 2158 protected BigDecimal toBigDecimal(final boolean strict, final Object val) { 2159 return isNullOperand(val)? controlNullOperand(strict, BigDecimal.ZERO) : toBigDecimal(val); 2160 } 2161 2162 /** 2163 * Coerce to a BigDecimal. 2164 * <p>Double.NaN, null and empty string coerce to zero.</p> 2165 * <p>Boolean false is 0, true is 1.</p> 2166 * 2167 * @param val The object to be coerced. 2168 * @return A BigDecimal. 2169 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2170 */ 2171 public BigDecimal toBigDecimal(final Object val) { 2172 if (val instanceof BigDecimal) { 2173 return roundBigDecimal((BigDecimal) val); 2174 } 2175 if (val instanceof Double) { 2176 if (Double.isNaN((Double) val)) { 2177 return BigDecimal.ZERO; 2178 } 2179 return roundBigDecimal(new BigDecimal(val.toString(), getMathContext())); 2180 } 2181 if (val instanceof Number) { 2182 return roundBigDecimal(parseBigDecimal(val.toString())); 2183 } 2184 if (val instanceof Boolean) { 2185 return BigDecimal.valueOf((boolean) val ? 1. : 0.); 2186 } 2187 if (val instanceof AtomicBoolean) { 2188 return BigDecimal.valueOf(((AtomicBoolean) val).get() ? 1L : 0L); 2189 } 2190 if (val instanceof String) { 2191 return roundBigDecimal(parseBigDecimal((String) val)); 2192 } 2193 if (val instanceof Character) { 2194 return new BigDecimal((Character) val); 2195 } 2196 if (val == null) { 2197 return controlNullOperand(strict, BigDecimal.ZERO); 2198 } 2199 throw new CoercionException("BigDecimal coercion: " 2200 + val.getClass().getName() + ":(" + val + ")"); 2201 } 2202 2203 /** 2204 * Coerce to a BigInteger. 2205 * <p>Double.NaN, null and empty string coerce to zero.</p> 2206 * <p>Boolean false is 0, true is 1.</p> 2207 * 2208 * @param strict true if the calling operator or casting is strict, false otherwise 2209 * @param val The object to be coerced. 2210 * @return A BigInteger 2211 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2212 * @since 3.3 2213 */ 2214 protected BigInteger toBigInteger(final boolean strict, final Object val) { 2215 return isNullOperand(val)? controlNullOperand(strict, BigInteger.ZERO) : toBigInteger(val); 2216 } 2217 2218 /** 2219 * Coerce to a BigInteger. 2220 * <p>Double.NaN, null and empty string coerce to zero.</p> 2221 * <p>Boolean false is 0, true is 1.</p> 2222 * 2223 * @param val The object to be coerced. 2224 * @return A BigInteger 2225 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2226 */ 2227 public BigInteger toBigInteger(final Object val) { 2228 if (val instanceof BigInteger) { 2229 return (BigInteger) val; 2230 } 2231 if (val instanceof Double) { 2232 final Double dval = (Double) val; 2233 if (Double.isNaN(dval)) { 2234 return BigInteger.ZERO; 2235 } 2236 return BigInteger.valueOf(dval.longValue()); 2237 } 2238 if (val instanceof BigDecimal) { 2239 return ((BigDecimal) val).toBigInteger(); 2240 } 2241 if (val instanceof Number) { 2242 return BigInteger.valueOf(((Number) val).longValue()); 2243 } 2244 if (val instanceof Boolean) { 2245 return (boolean) val ? BigInteger.ONE : BigInteger.ZERO; 2246 } 2247 if (val instanceof AtomicBoolean) { 2248 return ((AtomicBoolean) val).get() ? BigInteger.ONE : BigInteger.ZERO; 2249 } 2250 if (val instanceof String) { 2251 return parseBigInteger((String) val); 2252 } 2253 if (val instanceof Character) { 2254 final int i = (Character) val; 2255 return BigInteger.valueOf(i); 2256 } 2257 if (val == null) { 2258 return controlNullOperand(strict, BigInteger.ZERO); 2259 } 2260 throw new CoercionException("BigInteger coercion: " 2261 + val.getClass().getName() + ":(" + val + ")"); 2262 } 2263 2264 /** 2265 * Coerce to a primitive boolean. 2266 * <p>Double.NaN, null, "false" and empty string coerce to false.</p> 2267 * 2268 * @param val value to coerce 2269 * @param strict true if the calling operator or casting is strict, false otherwise 2270 * @return The boolean value if coercion is possible, true if value was not null. 2271 */ 2272 protected boolean toBoolean(final boolean strict, final Object val) { 2273 return isNullOperand(val)? controlNullOperand(strict, false) : toBoolean(val); 2274 } 2275 2276 /** 2277 * Coerce to a primitive boolean. 2278 * <p>Double.NaN, null, "false" and empty string coerce to false.</p> 2279 * 2280 * @param val value to coerce 2281 * @return The boolean value if coercion is possible, true if value was not null. 2282 */ 2283 public boolean toBoolean(final Object val) { 2284 if (val instanceof Boolean) { 2285 return (Boolean) val; 2286 } 2287 if (val instanceof Number) { 2288 final double number = toDouble(strict, val); 2289 return !Double.isNaN(number) && number != 0.d; 2290 } 2291 if (val instanceof AtomicBoolean) { 2292 return ((AtomicBoolean) val).get(); 2293 } 2294 if (val instanceof String) { 2295 final String strval = val.toString(); 2296 return !strval.isEmpty() && !"false".equals(strval); 2297 } 2298 if (val == null) { 2299 return controlNullOperand(strict, false); 2300 } 2301 // non-null value is true 2302 return true; 2303 } 2304 2305 /** 2306 * Coerce to a primitive double. 2307 * <p>Double.NaN, null and empty string coerce to zero.</p> 2308 * <p>Boolean false is 0, true is 1.</p> 2309 * 2310 * @param strict true if the calling operator or casting is strict, false otherwise 2311 * @param val value to coerce. 2312 * @return The double coerced value. 2313 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2314 * @since 3.3 2315 */ 2316 protected double toDouble(final boolean strict, final Object val) { 2317 return isNullOperand(val)? controlNullOperand(strict, 0.d) : toDouble(val); 2318 } 2319 2320 /** 2321 * Coerce to a primitive double. 2322 * <p>Double.NaN, null and empty string coerce to zero.</p> 2323 * <p>Boolean false is 0, true is 1.</p> 2324 * 2325 * @param val value to coerce. 2326 * @return The double coerced value. 2327 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2328 */ 2329 public double toDouble(final Object val) { 2330 if (val instanceof Double) { 2331 return (Double) val; 2332 } 2333 if (val instanceof Number) { 2334 return ((Number) val).doubleValue(); 2335 } 2336 if (val instanceof Boolean) { 2337 return (boolean) val ? 1. : 0.; 2338 } 2339 if (val instanceof AtomicBoolean) { 2340 return ((AtomicBoolean) val).get() ? 1. : 0.; 2341 } 2342 if (val instanceof String) { 2343 return parseDouble((String) val); 2344 } 2345 if (val instanceof Character) { 2346 return (Character) val; 2347 } 2348 if (val == null) { 2349 return controlNullOperand(strict, 0.d); 2350 } 2351 throw new CoercionException("Double coercion: " 2352 + val.getClass().getName() + ":(" + val + ")"); 2353 } 2354 2355 /** 2356 * Coerce to a primitive int. 2357 * <p>Double.NaN, null and empty string coerce to zero.</p> 2358 * <p>Boolean false is 0, true is 1.</p> 2359 * 2360 * @param strict true if the calling operator or casting is strict, false otherwise 2361 * @param val value to coerce 2362 * @return The value coerced to int 2363 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2364 * @since 3.3 2365 */ 2366 protected int toInteger(final boolean strict, final Object val) { 2367 return isNullOperand(val)? controlNullOperand(strict, 0) : toInteger(val); 2368 } 2369 2370 /** 2371 * Coerce to a primitive int. 2372 * <p>Double.NaN, null and empty string coerce to zero.</p> 2373 * <p>Boolean false is 0, true is 1.</p> 2374 * 2375 * @param val value to coerce 2376 * @return The value coerced to int 2377 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2378 */ 2379 public int toInteger(final Object val) { 2380 if (val instanceof Double) { 2381 final double dval = (Double) val; 2382 return Double.isNaN(dval)? 0 : (int) dval; 2383 } 2384 if (val instanceof Number) { 2385 return ((Number) val).intValue(); 2386 } 2387 if (val instanceof String) { 2388 return parseInteger((String) val); 2389 } 2390 if (val instanceof Boolean) { 2391 return (boolean) val ? 1 : 0; 2392 } 2393 if (val instanceof AtomicBoolean) { 2394 return ((AtomicBoolean) val).get() ? 1 : 0; 2395 } 2396 if (val instanceof Character) { 2397 return (Character) val; 2398 } 2399 if (val == null) { 2400 return controlNullOperand(strict, 0); 2401 } 2402 throw new CoercionException("Integer coercion: " 2403 + val.getClass().getName() + ":(" + val + ")"); 2404 } 2405 2406 /** 2407 * Coerce to a primitive long. 2408 * <p>Double.NaN, null and empty string coerce to zero.</p> 2409 * <p>Boolean false is 0, true is 1.</p> 2410 * 2411 * @param strict true if the calling operator or casting is strict, false otherwise 2412 * @param val value to coerce 2413 * @return The value coerced to long 2414 * @throws ArithmeticException if value is null and mode is strict or if coercion is not possible 2415 * @since 3.3 2416 */ 2417 protected long toLong(final boolean strict, final Object val) { 2418 return isNullOperand(val)? controlNullOperand(strict, 0L) : toLong(val); 2419 } 2420 2421 /** 2422 * Coerce to a primitive long. 2423 * <p>Double.NaN, null and empty string coerce to zero.</p> 2424 * <p>Boolean false is 0, true is 1.</p> 2425 * 2426 * @param val value to coerce 2427 * @return The value coerced to long 2428 * @throws ArithmeticException if value is null and mode is strict or if coercion is not possible 2429 */ 2430 public long toLong(final Object val) { 2431 if (val instanceof Double) { 2432 final double dval = (Double) val; 2433 return Double.isNaN(dval)? 0L : (long) dval; 2434 } 2435 if (val instanceof Number) { 2436 return ((Number) val).longValue(); 2437 } 2438 if (val instanceof String) { 2439 return parseLong((String) val); 2440 } 2441 if (val instanceof Boolean) { 2442 return (boolean) val ? 1L : 0L; 2443 } 2444 if (val instanceof AtomicBoolean) { 2445 return ((AtomicBoolean) val).get() ? 1L : 0L; 2446 } 2447 if (val instanceof Character) { 2448 return (Character) val; 2449 } 2450 if (val == null) { 2451 return controlNullOperand(strict, 0L); 2452 } 2453 throw new CoercionException("Long coercion: " 2454 + val.getClass().getName() + ":(" + val + ")"); 2455 } 2456 2457 /** 2458 * Coerce to a string. 2459 * <p>Double.NaN coerce to the empty string.</p> 2460 * 2461 * @param strict true if the calling operator or casting is strict, false otherwise 2462 * @param val value to coerce. 2463 * @return The String coerced value. 2464 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2465 * @since 3.3 2466 */ 2467 protected String toString(final boolean strict, final Object val) { 2468 return isNullOperand(val)? controlNullOperand(strict, "") : toString(val); 2469 } 2470 2471 /** 2472 * Coerce to a string. 2473 * <p>Double.NaN coerce to the empty string.</p> 2474 * 2475 * @param val value to coerce. 2476 * @return The String coerced value. 2477 * @throws ArithmeticException if val is null and mode is strict or if coercion is not possible 2478 */ 2479 public String toString(final Object val) { 2480 if (val instanceof Double) { 2481 final Double dval = (Double) val; 2482 if (Double.isNaN(dval)) { 2483 return ""; 2484 } 2485 return dval.toString(); 2486 } 2487 return val == null ? controlNullOperand(strict, "") : val.toString(); 2488 } 2489 2490 /** 2491 * Performs a bitwise xor. 2492 * 2493 * @param left The left operand 2494 * @param right The right operator 2495 * @return left ^ right 2496 */ 2497 public Object xor(final Object left, final Object right) { 2498 final long l = toLong(left); 2499 final long r = toLong(right); 2500 return l ^ r; 2501 } 2502 2503 /** 2504 * A CharSequence wrapper that throws ArithmeticException if the current thread is interrupted. 2505 * Used as the input to {@code Pattern.matcher()} so that catastrophic-backtracking regex matches 2506 * remain responsive to JEXL cancellation (which sets the thread interrupt flag). 2507 * The interrupt flag is checked every 256 {@code charAt} calls to limit overhead. 2508 */ 2509 private static final class InterruptibleCharSequence implements CharSequence { 2510 private final String seq; 2511 private int count; 2512 2513 private InterruptibleCharSequence(final String s) { 2514 this.seq = s; 2515 } 2516 2517 @Override 2518 public char charAt(final int index) { 2519 if ((++count & 0xff) == 0 && Thread.currentThread().isInterrupted()) { 2520 throw new ArithmeticException("Operation interrupted"); 2521 } 2522 return seq.charAt(index); 2523 } 2524 2525 @Override 2526 public int length() { 2527 return seq.length(); 2528 } 2529 2530 @Override 2531 public CharSequence subSequence(final int start, final int end) { 2532 return new InterruptibleCharSequence(seq.substring(start, end)); 2533 } 2534 2535 @Override 2536 public String toString() { 2537 return seq; 2538 } 2539 } 2540}