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