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