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