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