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 */ 017package org.apache.commons.el; 018 019import java.beans.PropertyEditor; 020import java.beans.PropertyEditorManager; 021import java.math.BigDecimal; 022import java.math.BigInteger; 023 024import javax.servlet.jsp.el.ELException; 025 026import org.apache.commons.logging.Log; 027import org.apache.commons.logging.LogFactory; 028 029/** 030 * 031 * <p>This class contains the logic for coercing data types before 032 * operators are applied to them. 033 * 034 * <p>The following is the list of rules applied for various type 035 * conversions. 036 * 037 * <ul><pre> 038 * Applying arithmetic operator 039 * Binary operator - A {+,-,*} B 040 * if A and B are null 041 * return 0 042 * if A or B is BigDecimal, coerce both to BigDecimal and then: 043 * if operator is +, return <code>A.add(B)</code> 044 * if operator is -, return <code>A.subtract(B)</code> 045 * if operator is *, return <code>A.multiply(B)</code> 046 * if A or B is Float, Double, or String containing ".", "e", or "E" 047 * if A or B is BigInteger, coerce both A and B to BigDecimal and apply operator 048 * coerce both A and B to Double and apply operator 049 * if A or B is BigInteger, coerce both to BigInteger and then: 050 * if operator is +, return <code>A.add(B)</code> 051 * if operator is -, return <code>A.subtract(B)</code> 052 * if operator is *, return <code>A.multiply(B)</code> 053 * otherwise 054 * coerce both A and B to Long 055 * apply operator 056 * if operator results in exception (such as divide by 0), error 057 * 058 * Binary operator - A {/,div} B 059 * if A and B are null 060 * return 0 061 * if A or B is a BigDecimal or BigInteger, coerce both to BigDecimal and 062 * return <code>A.divide(B, BigDecimal.ROUND_HALF_UP)</code> 063 * otherwise 064 * coerce both A and B to Double 065 * apply operator 066 * if operator results in exception (such as divide by 0), error 067 * 068 * Binary operator - A {%,mod} B 069 * if A and B are null 070 * return 0 071 * if A or B is BigDecimal, Float, Double, or String containing ".", "e" or "E" 072 * coerce both to Double 073 * apply operator 074 * if A or B is BigInteger, coerce both to BigInteger and return 075 * <code>A.remainder(B)</code> 076 * otherwise 077 * coerce both A and B to Long 078 * apply operator 079 * if operator results in exception (such as divide by 0), error 080 * 081 * Unary minus operator - -A 082 * if A is null 083 * return 0 084 * if A is BigInteger or BigDecimal, return <code>A.negate()</code> 085 * if A is String 086 * if A contains ".", "e", or "E" 087 * coerce to Double, apply operator 088 * otherwise 089 * coerce to a Long and apply operator 090 * if A is Byte,Short,Integer,Long,Float,Double 091 * retain type, apply operator 092 * if operator results in exception, error 093 * otherwise 094 * error 095 * 096 * Applying "empty" operator - empty A 097 * if A is null 098 * return true 099 * if A is zero-length String 100 * return true 101 * if A is zero-length array 102 * return true 103 * if A is List and ((List) A).isEmpty() 104 * return true 105 * if A is Map and ((Map) A).isEmpty() 106 * return true 107 * if A is Collection an ((Collection) A).isEmpty() 108 * return true 109 * otherwise 110 * return false 111 * 112 * Applying logical operators 113 * Binary operator - A {and,or} B 114 * coerce both A and B to Boolean, apply operator 115 * NOTE - operator stops as soon as expression can be determined, i.e., 116 * A and B and C and D - if B is false, then only A and B is evaluated 117 * Unary not operator - not A 118 * coerce A to Boolean, apply operator 119 * 120 * Applying relational operator 121 * A {<,>,<=,>=,lt,gt,lte,gte} B 122 * if A==B 123 * if operator is >= or <= 124 * return true 125 * otherwise 126 * return false 127 * if A or B is null 128 * return false 129 * if A or B is BigDecimal, coerce both A and B to BigDecimal and use the 130 * return value of <code>A.compareTo(B)</code> 131 * if A or B is Float or Double 132 * coerce both A and B to Double 133 * apply operator 134 * if A or B is BigInteger, coerce both A and B to BigInteger and use the 135 * return value of <code>A.compareTo(B)</code> 136 * if A or B is Byte,Short,Character,Integer,Long 137 * coerce both A and B to Long 138 * apply operator 139 * if A or B is String 140 * coerce both A and B to String, compare lexically 141 * if A is Comparable 142 * if A.compareTo (B) throws exception 143 * error 144 * otherwise 145 * use result of A.compareTo(B) 146 * if B is Comparable 147 * if B.compareTo (A) throws exception 148 * error 149 * otherwise 150 * use result of B.compareTo(A) 151 * otherwise 152 * error 153 * 154 * Applying equality operator 155 * A {==,!=} B 156 * if A==B 157 * apply operator 158 * if A or B is null 159 * return false for ==, true for != 160 * if A or B is BigDecimal, coerce both A and B to BigDecimal and then: 161 * if operator is == or eq, return <code>A.equals(B)</code> 162 * if operator is != or ne, return <code>!A.equals(B)</code> 163 * if A or B is Float or Double 164 * coerce both A and B to Double 165 * apply operator 166 * if A or B is BigInteger, coerce both A and B to BigInteger and then: 167 * if operator is == or eq, return <code>A.equals(B)</code> 168 * if operator is != or ne, return <code>!A.equals(B)</code> 169 * if A or B is Byte,Short,Character,Integer,Long 170 * coerce both A and B to Long 171 * apply operator 172 * if A or B is Boolean 173 * coerce both A and B to Boolean 174 * apply operator 175 * if A or B is String 176 * coerce both A and B to String, compare lexically 177 * otherwise 178 * if an error occurs while calling A.equals(B) 179 * error 180 * apply operator to result of A.equals(B) 181 * 182 * coercions 183 * 184 * coerce A to String 185 * A is String 186 * return A 187 * A is null 188 * return "" 189 * A.toString throws exception 190 * error 191 * otherwise 192 * return A.toString 193 * 194 * coerce A to Number type N 195 * A is null or "" 196 * return 0 197 * A is Character 198 * convert to short, apply following rules 199 * A is Boolean 200 * error 201 * A is Number type N 202 * return A 203 * A is Number, coerce quietly to type N using the following algorithm 204 * If N is BigInteger 205 * If A is BigDecimal, return <code>A.toBigInteger()</code> 206 * Otherwise, return <code>BigInteger.valueOf(A.longValue())</code> 207 * if N is BigDecimal 208 * If A is a BigInteger, return <code>new BigDecimal(A)</code> 209 * Otherwise, return <code>new BigDecimal(A.doubleValue())</code> 210 * If N is Byte, return <code>new Byte(A.byteValue())</code> 211 * If N is Short, return <code>new Short(A.shortValue())</code> 212 * If N is Integer, return <code>new Integer(A.integerValue())</code> 213 * If N is Long, return <code>new Long(A.longValue())</code> 214 * If N is Float, return <code>new Float(A.floatValue())</code> 215 * If N is Double, return <code>new Double(A.doubleValue())</code> 216 * otherwise ERROR 217 * A is String 218 * If N is BigDecimal then: 219 * If <code>new BigDecimal(A)</code> throws an exception then ERROR 220 * Otherwise, return <code>new BigDecimal(A)</code> 221 * If N is BigInteger then: 222 * If <code>new BigInteger(A)</code> throws an exception, then ERROR 223 * Otherwise, return <code>new BigInteger(A)</code> 224 * new <code>N.valueOf(A)</code> throws exception 225 * error 226 * return <code>N.valueOf(A)</code> 227 * otherwise 228 * error 229 * 230 * coerce A to Character should be 231 * A is null or "" 232 * return (char) 0 233 * A is Character 234 * return A 235 * A is Boolean 236 * error 237 * A is Number with less precision than short 238 * coerce quietly - return (char) A 239 * A is Number with greater precision than short 240 * coerce quietly - return (char) A 241 * A is String 242 * return A.charAt (0) 243 * otherwise 244 * error 245 * 246 * coerce A to Boolean 247 * A is null or "" 248 * return false 249 * A is Boolean 250 * return A 251 * A is String 252 * Boolean.valueOf(A) throws exception 253 * error 254 * return Boolean.valueOf(A) 255 * otherwise 256 * error 257 * 258 * coerce A to any other type T 259 * A is null 260 * return null 261 * A is assignable to T 262 * coerce quietly 263 * A is String 264 * T has no PropertyEditor 265 * if A is "", return null 266 * otherwise error 267 * T's PropertyEditor throws exception 268 * if A is "", return null 269 * otherwise error 270 * otherwise 271 * apply T's PropertyEditor 272 * otherwise 273 * error 274 * </pre></ul> 275 * 276 * @author Nathan Abramson - Art Technology Group 277 * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: bayard $ 278 **/ 279 280public class Coercions 281{ 282 //------------------------------------- 283 // Constants 284 //------------------------------------- 285 private static final Number ZERO = new Integer(0); 286 private static Log log = LogFactory.getLog(Coercions.class); 287 288 //------------------------------------- 289 /** 290 * 291 * Coerces the given value to the specified class. 292 **/ 293 public static Object coerce (Object pValue, 294 Class pClass) 295 throws ELException 296 { 297 if (pClass == String.class) { 298 return coerceToString (pValue); 299 } 300 else if (isNumberClass (pClass)) { 301 return coerceToPrimitiveNumber (pValue, pClass); 302 } 303 else if (pClass == Character.class || 304 pClass == Character.TYPE) { 305 return coerceToCharacter (pValue); 306 } 307 else if (pClass == Boolean.class || 308 pClass == Boolean.TYPE) { 309 return coerceToBoolean (pValue); 310 } 311 else { 312 return coerceToObject (pValue, pClass); 313 } 314 } 315 316 //------------------------------------- 317 /** 318 * 319 * Returns true if the given class is Byte, Short, Integer, Long, 320 * Float, Double, BigInteger, or BigDecimal 321 **/ 322 static boolean isNumberClass (Class pClass) 323 { 324 return 325 pClass == Byte.class || 326 pClass == Byte.TYPE || 327 pClass == Short.class || 328 pClass == Short.TYPE || 329 pClass == Integer.class || 330 pClass == Integer.TYPE || 331 pClass == Long.class || 332 pClass == Long.TYPE || 333 pClass == Float.class || 334 pClass == Float.TYPE || 335 pClass == Double.class || 336 pClass == Double.TYPE || 337 pClass == BigInteger.class || 338 pClass == BigDecimal.class; 339 } 340 341 //------------------------------------- 342 /** 343 * 344 * Coerces the specified value to a String 345 **/ 346 public static String coerceToString (Object pValue) 347 throws ELException 348 { 349 if (pValue == null) { 350 return ""; 351 } 352 else if (pValue instanceof String) { 353 return (String) pValue; 354 } 355 else { 356 try { 357 return pValue.toString (); 358 } 359 catch (Exception exc) { 360 if (log.isErrorEnabled()) { 361 String message = MessageUtil.getMessageWithArgs( 362 Constants.TOSTRING_EXCEPTION, 363 pValue.getClass().getName()); 364 log.error(message, exc); 365 throw new ELException(exc); 366 } 367 return ""; 368 } 369 } 370 } 371 372 //------------------------------------- 373 /** 374 * 375 * Coerces a value to the given primitive number class 376 **/ 377 public static Number coerceToPrimitiveNumber (Object pValue, 378 Class pClass) 379 throws ELException 380 { 381 if (pValue == null || 382 "".equals (pValue)) { 383 return coerceToPrimitiveNumber (ZERO, pClass); 384 } 385 else if (pValue instanceof Character) { 386 char val = ((Character) pValue).charValue (); 387 return coerceToPrimitiveNumber (new Short((short) val), pClass); 388 } 389 else if (pValue instanceof Boolean) { 390 if (log.isErrorEnabled()) { 391 String message = MessageUtil.getMessageWithArgs( 392 Constants.BOOLEAN_TO_NUMBER, pValue, pClass.getName()); 393 log.error(message); 394 throw new ELException(message); 395 } 396 return coerceToPrimitiveNumber(ZERO, pClass); 397 } 398 else if (pValue.getClass () == pClass) { 399 return (Number) pValue; 400 } 401 else if (pValue instanceof Number) { 402 return coerceToPrimitiveNumber ((Number) pValue, pClass); 403 } 404 else if (pValue instanceof String) { 405 try { 406 return coerceToPrimitiveNumber ((String) pValue, pClass); 407 } 408 catch (Exception exc) { 409 if (log.isErrorEnabled()) { 410 String message = MessageUtil.getMessageWithArgs( 411 Constants.STRING_TO_NUMBER_EXCEPTION, 412 (String) pValue, pClass.getName()); 413 log.error(message); 414 throw new ELException(message); 415 } 416 return coerceToPrimitiveNumber (ZERO, pClass); 417 } 418 } 419 else { 420 if (log.isErrorEnabled()) { 421 String message = MessageUtil.getMessageWithArgs( 422 Constants.COERCE_TO_NUMBER, 423 pValue.getClass().getName(), 424 pClass.getName()); 425 log.error(message); 426 throw new ELException(message); 427 } 428 return coerceToPrimitiveNumber (0, pClass); 429 } 430 } 431 432 //------------------------------------- 433 /** 434 * 435 * Coerces a value to an Integer, returning null if the coercion 436 * isn't possible. 437 **/ 438 public static Integer coerceToInteger (Object pValue) 439 throws ELException 440 { 441 if (pValue == null) { 442 return null; 443 } 444 else if (pValue instanceof Character) { 445 return PrimitiveObjects.getInteger 446 ((int) (((Character) pValue).charValue ())); 447 } 448 else if (pValue instanceof Boolean) { 449 if (log.isWarnEnabled()) { 450 log.warn( 451 MessageUtil.getMessageWithArgs( 452 Constants.BOOLEAN_TO_NUMBER, pValue, Integer.class.getName())); 453 } 454 return PrimitiveObjects.getInteger 455 (((Boolean) pValue).booleanValue () ? 1 : 0); 456 } 457 else if (pValue instanceof Integer) { 458 return (Integer) pValue; 459 } 460 else if (pValue instanceof Number) { 461 return PrimitiveObjects.getInteger (((Number) pValue).intValue ()); 462 } 463 else if (pValue instanceof String) { 464 try { 465 return Integer.valueOf ((String) pValue); 466 } 467 catch (Exception exc) { 468 if (log.isWarnEnabled()) { 469 log.warn( 470 MessageUtil.getMessageWithArgs( 471 Constants.STRING_TO_NUMBER_EXCEPTION, 472 (String) pValue, 473 Integer.class.getName())); 474 } 475 return null; 476 } 477 } 478 else { 479 if (log.isWarnEnabled()) { 480 log.warn( 481 MessageUtil.getMessageWithArgs( 482 Constants.COERCE_TO_NUMBER, 483 pValue.getClass().getName(), 484 Integer.class.getName())); 485 } 486 return null; 487 } 488 } 489 490 //------------------------------------- 491 /** 492 * 493 * Coerces a long to the given primitive number class 494 **/ 495 static Number coerceToPrimitiveNumber (long pValue, 496 Class pClass) 497 throws ELException 498 { 499 if (pClass == Byte.class || pClass == Byte.TYPE) { 500 return PrimitiveObjects.getByte ((byte) pValue); 501 } 502 else if (pClass == Short.class || pClass == Short.TYPE) { 503 return PrimitiveObjects.getShort ((short) pValue); 504 } 505 else if (pClass == Integer.class || pClass == Integer.TYPE) { 506 return PrimitiveObjects.getInteger ((int) pValue); 507 } 508 else if (pClass == Long.class || pClass == Long.TYPE) { 509 return PrimitiveObjects.getLong (pValue); 510 } 511 else if (pClass == Float.class || pClass == Float.TYPE) { 512 return PrimitiveObjects.getFloat ((float) pValue); 513 } 514 else if (pClass == Double.class || pClass == Double.TYPE) { 515 return PrimitiveObjects.getDouble ((double) pValue); 516 } 517 else { 518 return PrimitiveObjects.getInteger (0); 519 } 520 } 521 522 //------------------------------------- 523 /** 524 * 525 * Coerces a double to the given primitive number class 526 **/ 527 static Number coerceToPrimitiveNumber (double pValue, 528 Class pClass) 529 throws ELException 530 { 531 if (pClass == Byte.class || pClass == Byte.TYPE) { 532 return PrimitiveObjects.getByte ((byte) pValue); 533 } 534 else if (pClass == Short.class || pClass == Short.TYPE) { 535 return PrimitiveObjects.getShort ((short) pValue); 536 } 537 else if (pClass == Integer.class || pClass == Integer.TYPE) { 538 return PrimitiveObjects.getInteger ((int) pValue); 539 } 540 else if (pClass == Long.class || pClass == Long.TYPE) { 541 return PrimitiveObjects.getLong ((long) pValue); 542 } 543 else if (pClass == Float.class || pClass == Float.TYPE) { 544 return PrimitiveObjects.getFloat ((float) pValue); 545 } 546 else if (pClass == Double.class || pClass == Double.TYPE) { 547 return PrimitiveObjects.getDouble (pValue); 548 } 549 else { 550 return PrimitiveObjects.getInteger (0); 551 } 552 } 553 554 //------------------------------------- 555 /** 556 * 557 * Coerces a Number to the given primitive number class 558 **/ 559 static Number coerceToPrimitiveNumber (Number pValue, Class pClass) 560 throws ELException 561 { 562 if (pClass == Byte.class || pClass == Byte.TYPE) { 563 return PrimitiveObjects.getByte (pValue.byteValue ()); 564 } 565 else if (pClass == Short.class || pClass == Short.TYPE) { 566 return PrimitiveObjects.getShort (pValue.shortValue ()); 567 } 568 else if (pClass == Integer.class || pClass == Integer.TYPE) { 569 return PrimitiveObjects.getInteger (pValue.intValue ()); 570 } 571 else if (pClass == Long.class || pClass == Long.TYPE) { 572 return PrimitiveObjects.getLong (pValue.longValue ()); 573 } 574 else if (pClass == Float.class || pClass == Float.TYPE) { 575 return PrimitiveObjects.getFloat (pValue.floatValue ()); 576 } 577 else if (pClass == Double.class || pClass == Double.TYPE) { 578 return PrimitiveObjects.getDouble (pValue.doubleValue ()); 579 } 580 else if (pClass == BigInteger.class) { 581 if (pValue instanceof BigDecimal) 582 return ((BigDecimal) pValue).toBigInteger(); 583 else 584 return BigInteger.valueOf(pValue.longValue()); 585 } 586 else if (pClass == BigDecimal.class) { 587 if (pValue instanceof BigInteger) 588 return new BigDecimal((BigInteger) pValue); 589 else 590 return new BigDecimal(pValue.doubleValue()); 591 } 592 else { 593 return PrimitiveObjects.getInteger (0); 594 } 595 } 596 597 //------------------------------------- 598 /** 599 * 600 * Coerces a String to the given primitive number class 601 **/ 602 static Number coerceToPrimitiveNumber (String pValue, Class pClass) 603 throws ELException 604 { 605 if (pClass == Byte.class || pClass == Byte.TYPE) { 606 return Byte.valueOf (pValue); 607 } 608 else if (pClass == Short.class || pClass == Short.TYPE) { 609 return Short.valueOf (pValue); 610 } 611 else if (pClass == Integer.class || pClass == Integer.TYPE) { 612 return Integer.valueOf (pValue); 613 } 614 else if (pClass == Long.class || pClass == Long.TYPE) { 615 return Long.valueOf (pValue); 616 } 617 else if (pClass == Float.class || pClass == Float.TYPE) { 618 return Float.valueOf (pValue); 619 } 620 else if (pClass == Double.class || pClass == Double.TYPE) { 621 return Double.valueOf (pValue); 622 } 623 else if (pClass == BigInteger.class) { 624 return new BigInteger(pValue); 625 } 626 else if (pClass == BigDecimal.class) { 627 return new BigDecimal(pValue); 628 } 629 else { 630 return PrimitiveObjects.getInteger (0); 631 } 632 } 633 634 //------------------------------------- 635 /** 636 * 637 * Coerces a value to a Character 638 **/ 639 public static Character coerceToCharacter (Object pValue) 640 throws ELException 641 { 642 if (pValue == null || 643 "".equals (pValue)) { 644 return PrimitiveObjects.getCharacter ((char) 0); 645 } 646 else if (pValue instanceof Character) { 647 return (Character) pValue; 648 } 649 else if (pValue instanceof Boolean) { 650 if (log.isErrorEnabled()) { 651 String message = MessageUtil.getMessageWithArgs( 652 Constants.BOOLEAN_TO_CHARACTER, pValue); 653 log.error(message); 654 throw new ELException(message); 655 } 656 return PrimitiveObjects.getCharacter ((char) 0); 657 } 658 else if (pValue instanceof Number) { 659 return PrimitiveObjects.getCharacter 660 ((char) ((Number) pValue).shortValue ()); 661 } 662 else if (pValue instanceof String) { 663 String str = (String) pValue; 664 return PrimitiveObjects.getCharacter (str.charAt (0)); 665 } 666 else { 667 if (log.isErrorEnabled()) { 668 String message = MessageUtil.getMessageWithArgs( 669 Constants.COERCE_TO_CHARACTER, 670 pValue.getClass().getName()); 671 log.error(message); 672 throw new ELException(message); 673 } 674 return PrimitiveObjects.getCharacter ((char) 0); 675 } 676 } 677 678 //------------------------------------- 679 /** 680 * 681 * Coerces a value to a Boolean 682 **/ 683 public static Boolean coerceToBoolean (Object pValue) 684 throws ELException 685 { 686 if (pValue == null || 687 "".equals (pValue)) { 688 return Boolean.FALSE; 689 } 690 else if (pValue instanceof Boolean) { 691 return (Boolean) pValue; 692 } 693 else if (pValue instanceof String) { 694 String str = (String) pValue; 695 try { 696 return Boolean.valueOf (str); 697 } 698 catch (Exception exc) { 699 if (log.isErrorEnabled()) { 700 String message = MessageUtil.getMessageWithArgs( 701 Constants.STRING_TO_BOOLEAN, (String) pValue); 702 log.error(message, exc); 703 throw new ELException(message, exc); 704 } 705 return Boolean.FALSE; 706 } 707 } 708 else { 709 if (log.isErrorEnabled()) { 710 String message = MessageUtil.getMessageWithArgs( 711 Constants.COERCE_TO_BOOLEAN, 712 pValue.getClass().getName()); 713 log.error(message); 714 throw new ELException(message); 715 } 716 return Boolean.TRUE; 717 } 718 } 719 720 //------------------------------------- 721 /** 722 * 723 * Coerces a value to the specified Class that is not covered by any 724 * of the above cases 725 **/ 726 public static Object coerceToObject (Object pValue, Class pClass) 727 throws ELException 728 { 729 if (pValue == null) { 730 return null; 731 } 732 else if (pClass.isAssignableFrom (pValue.getClass ())) { 733 return pValue; 734 } 735 else if (pValue instanceof String) { 736 String str = (String) pValue; 737 PropertyEditor pe = PropertyEditorManager.findEditor (pClass); 738 if (pe == null) { 739 if ("".equals (str)) { 740 return null; 741 } 742 else { 743 if (log.isErrorEnabled()) { 744 String message = MessageUtil.getMessageWithArgs( 745 Constants.NO_PROPERTY_EDITOR, 746 str, pClass.getName()); 747 log.error(message); 748 throw new ELException(message); 749 } 750 return null; 751 } 752 } 753 try { 754 pe.setAsText (str); 755 return pe.getValue (); 756 } 757 catch (IllegalArgumentException exc) { 758 if ("".equals (str)) { 759 return null; 760 } 761 else { 762 if (log.isErrorEnabled()) { 763 String message = MessageUtil.getMessageWithArgs( 764 Constants.PROPERTY_EDITOR_ERROR, 765 pValue, 766 pClass.getName()); 767 log.error(message, exc); 768 throw new ELException(message, exc); 769 } 770 return null; 771 } 772 } 773 } 774 else { 775 if (log.isErrorEnabled()) { 776 String message = MessageUtil.getMessageWithArgs( 777 Constants.COERCE_TO_OBJECT, 778 pValue.getClass().getName(), 779 pClass.getName()); 780 log.error(message); 781 throw new ELException(message); 782 } 783 return null; 784 } 785 } 786 787 //------------------------------------- 788 // Applying operators 789 //------------------------------------- 790 /** 791 * 792 * Performs all of the necessary type conversions, then calls on the 793 * appropriate operator. 794 **/ 795 public static Object applyArithmeticOperator 796 (Object pLeft, 797 Object pRight, 798 ArithmeticOperator pOperator) 799 throws ELException 800 { 801 if (pLeft == null && 802 pRight == null) { 803 if (log.isWarnEnabled()) { 804 log.warn( 805 MessageUtil.getMessageWithArgs( 806 Constants.ARITH_OP_NULL, 807 pOperator.getOperatorSymbol())); 808 } 809 return PrimitiveObjects.getInteger (0); 810 } 811 812 else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) { 813 BigDecimal left = (BigDecimal) 814 coerceToPrimitiveNumber(pLeft, BigDecimal.class); 815 BigDecimal right = (BigDecimal) 816 coerceToPrimitiveNumber(pRight, BigDecimal.class); 817 return pOperator.apply(left, right); 818 } 819 820 else if (isFloatingPointType(pLeft) || 821 isFloatingPointType(pRight) || 822 isFloatingPointString(pLeft) || 823 isFloatingPointString(pRight)) { 824 if (isBigInteger(pLeft) || isBigInteger(pRight)) { 825 BigDecimal left = (BigDecimal) 826 coerceToPrimitiveNumber(pLeft, BigDecimal.class); 827 BigDecimal right = (BigDecimal) 828 coerceToPrimitiveNumber(pRight, BigDecimal.class); 829 return pOperator.apply(left, right); 830 } else { 831 double left = 832 coerceToPrimitiveNumber(pLeft, Double.class). 833 doubleValue(); 834 double right = 835 coerceToPrimitiveNumber(pRight, Double.class). 836 doubleValue(); 837 return 838 PrimitiveObjects.getDouble(pOperator.apply(left, right)); 839 } 840 } 841 842 else if (isBigInteger(pLeft) || isBigInteger(pRight)) { 843 BigInteger left = (BigInteger) 844 coerceToPrimitiveNumber(pLeft, BigInteger.class); 845 BigInteger right = (BigInteger) 846 coerceToPrimitiveNumber(pRight, BigInteger.class); 847 return pOperator.apply(left, right); 848 } 849 850 else { 851 long left = 852 coerceToPrimitiveNumber (pLeft, Long.class). 853 longValue (); 854 long right = 855 coerceToPrimitiveNumber (pRight, Long.class). 856 longValue (); 857 return 858 PrimitiveObjects.getLong (pOperator.apply (left, right)); 859 } 860 } 861 862 //------------------------------------- 863 /** 864 * 865 * Performs all of the necessary type conversions, then calls on the 866 * appropriate operator. 867 **/ 868 public static Object applyRelationalOperator 869 (Object pLeft, 870 Object pRight, 871 RelationalOperator pOperator) 872 throws ELException 873 { 874 if (isBigDecimal(pLeft) || isBigDecimal(pRight)) { 875 BigDecimal left = (BigDecimal) 876 coerceToPrimitiveNumber(pLeft, BigDecimal.class); 877 BigDecimal right = (BigDecimal) 878 coerceToPrimitiveNumber(pRight, BigDecimal.class); 879 return PrimitiveObjects.getBoolean(pOperator.apply(left, right)); 880 } 881 882 else if (isFloatingPointType (pLeft) || 883 isFloatingPointType (pRight)) { 884 double left = 885 coerceToPrimitiveNumber (pLeft, Double.class). 886 doubleValue (); 887 double right = 888 coerceToPrimitiveNumber (pRight, Double.class). 889 doubleValue (); 890 return 891 PrimitiveObjects.getBoolean (pOperator.apply (left, right)); 892 } 893 894 else if (isBigInteger(pLeft) || isBigInteger(pRight)) { 895 BigInteger left = (BigInteger) 896 coerceToPrimitiveNumber(pLeft, BigInteger.class); 897 BigInteger right = (BigInteger) 898 coerceToPrimitiveNumber(pRight, BigInteger.class); 899 return PrimitiveObjects.getBoolean(pOperator.apply(left, right)); 900 } 901 902 else if (isIntegerType (pLeft) || 903 isIntegerType (pRight)) { 904 long left = 905 coerceToPrimitiveNumber (pLeft, Long.class). 906 longValue (); 907 long right = 908 coerceToPrimitiveNumber (pRight, Long.class). 909 longValue (); 910 return 911 PrimitiveObjects.getBoolean (pOperator.apply (left, right)); 912 } 913 914 else if (pLeft instanceof String || 915 pRight instanceof String) { 916 String left = coerceToString (pLeft); 917 String right = coerceToString (pRight); 918 return 919 PrimitiveObjects.getBoolean (pOperator.apply (left, right)); 920 } 921 922 else if (pLeft instanceof Comparable) { 923 try { 924 int result = ((Comparable) pLeft).compareTo (pRight); 925 return 926 PrimitiveObjects.getBoolean 927 (pOperator.apply (result, -result)); 928 } 929 catch (Exception exc) { 930 if (log.isErrorEnabled()) { 931 String message = MessageUtil.getMessageWithArgs( 932 Constants.COMPARABLE_ERROR, 933 pLeft.getClass().getName(), 934 (pRight == null) ? "null" : pRight.getClass().getName(), 935 pOperator.getOperatorSymbol()); 936 log.error(message, exc); 937 throw new ELException(message, exc); 938 } 939 return Boolean.FALSE; 940 } 941 } 942 943 else if (pRight instanceof Comparable) { 944 try { 945 int result = ((Comparable) pRight).compareTo (pLeft); 946 return 947 PrimitiveObjects.getBoolean 948 (pOperator.apply (-result, result)); 949 } 950 catch (Exception exc) { 951 if (log.isErrorEnabled()) { 952 String message = MessageUtil.getMessageWithArgs( 953 Constants.COMPARABLE_ERROR, 954 pRight.getClass().getName(), 955 (pLeft == null) ? "null" : pLeft.getClass().getName(), 956 pOperator.getOperatorSymbol()); 957 log.error(message, exc); 958 throw new ELException(message, exc); 959 } 960 return Boolean.FALSE; 961 } 962 } 963 964 else { 965 if (log.isErrorEnabled()) { 966 String message = MessageUtil.getMessageWithArgs( 967 Constants.ARITH_OP_BAD_TYPE, 968 pOperator.getOperatorSymbol(), 969 pLeft.getClass().getName(), 970 pRight.getClass().getName()); 971 log.error(message); 972 throw new ELException(message); 973 } 974 return Boolean.FALSE; 975 } 976 } 977 978 //------------------------------------- 979 /** 980 * 981 * Performs all of the necessary type conversions, then calls on the 982 * appropriate operator. 983 **/ 984 public static Object applyEqualityOperator 985 (Object pLeft, 986 Object pRight, 987 EqualityOperator pOperator) 988 throws ELException 989 { 990 if (pLeft == pRight) { 991 return PrimitiveObjects.getBoolean (pOperator.apply (true)); 992 } 993 994 else if (pLeft == null || 995 pRight == null) { 996 return PrimitiveObjects.getBoolean (pOperator.apply (false)); 997 } 998 999 else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) { 1000 BigDecimal left = (BigDecimal) 1001 coerceToPrimitiveNumber(pLeft, BigDecimal.class); 1002 BigDecimal right = (BigDecimal) 1003 coerceToPrimitiveNumber(pRight, BigDecimal.class); 1004 return PrimitiveObjects.getBoolean(pOperator.apply(left.equals(right))); 1005 } 1006 1007 else if (isFloatingPointType (pLeft) || 1008 isFloatingPointType (pRight)) { 1009 double left = 1010 coerceToPrimitiveNumber (pLeft, Double.class). 1011 doubleValue (); 1012 double right = 1013 coerceToPrimitiveNumber (pRight, Double.class). 1014 doubleValue (); 1015 return 1016 PrimitiveObjects.getBoolean 1017 (pOperator.apply (left == right)); 1018 } 1019 1020 else if (isBigInteger(pLeft) || isBigInteger(pRight)) { 1021 BigInteger left = (BigInteger) 1022 coerceToPrimitiveNumber(pLeft, BigInteger.class); 1023 BigInteger right = (BigInteger) 1024 coerceToPrimitiveNumber(pRight, BigInteger.class); 1025 return PrimitiveObjects.getBoolean(pOperator.apply(left.equals(right))); 1026 } 1027 1028 else if (isIntegerType (pLeft) || 1029 isIntegerType (pRight)) { 1030 long left = 1031 coerceToPrimitiveNumber (pLeft, Long.class). 1032 longValue (); 1033 long right = 1034 coerceToPrimitiveNumber (pRight, Long.class). 1035 longValue (); 1036 return 1037 PrimitiveObjects.getBoolean 1038 (pOperator.apply (left == right)); 1039 } 1040 1041 else if (pLeft instanceof Boolean || 1042 pRight instanceof Boolean) { 1043 boolean left = coerceToBoolean (pLeft).booleanValue (); 1044 boolean right = coerceToBoolean (pRight).booleanValue (); 1045 return 1046 PrimitiveObjects.getBoolean 1047 (pOperator.apply (left == right)); 1048 } 1049 1050 else if (pLeft instanceof String || 1051 pRight instanceof String) { 1052 String left = coerceToString (pLeft); 1053 String right = coerceToString (pRight); 1054 return 1055 PrimitiveObjects.getBoolean 1056 (pOperator.apply (left.equals (right))); 1057 } 1058 1059 else { 1060 try { 1061 return 1062 PrimitiveObjects.getBoolean 1063 (pOperator.apply (pLeft.equals (pRight))); 1064 } 1065 catch (Exception exc) { 1066 if (log.isErrorEnabled()) { 1067 String message = MessageUtil.getMessageWithArgs( 1068 Constants.ERROR_IN_EQUALS, 1069 pLeft.getClass().getName(), 1070 pRight.getClass().getName(), 1071 pOperator.getOperatorSymbol()); 1072 log.error(message, exc); 1073 throw new ELException(message, exc); 1074 } 1075 return Boolean.FALSE; 1076 } 1077 } 1078 } 1079 1080 //------------------------------------- 1081 /** 1082 * 1083 * Returns true if the given Object is of a floating point type 1084 **/ 1085 public static boolean isFloatingPointType (Object pObject) 1086 { 1087 return 1088 pObject != null && 1089 isFloatingPointType (pObject.getClass ()); 1090 } 1091 1092 //------------------------------------- 1093 /** 1094 * 1095 * Returns true if the given class is of a floating point type 1096 **/ 1097 public static boolean isFloatingPointType (Class pClass) 1098 { 1099 return 1100 pClass == Float.class || 1101 pClass == Float.TYPE || 1102 pClass == Double.class || 1103 pClass == Double.TYPE; 1104 } 1105 1106 //------------------------------------- 1107 /** 1108 * 1109 * Returns true if the given string might contain a floating point 1110 * number - i.e., it contains ".", "e", or "E" 1111 **/ 1112 public static boolean isFloatingPointString (Object pObject) 1113 { 1114 if (pObject instanceof String) { 1115 String str = (String) pObject; 1116 int len = str.length (); 1117 for (int i = 0; i < len; i++) { 1118 char ch = str.charAt (i); 1119 if (ch == '.' || 1120 ch == 'e' || 1121 ch == 'E') { 1122 return true; 1123 } 1124 } 1125 return false; 1126 } 1127 else { 1128 return false; 1129 } 1130 } 1131 1132 //------------------------------------- 1133 /** 1134 * 1135 * Returns true if the given Object is of an integer type 1136 **/ 1137 public static boolean isIntegerType (Object pObject) 1138 { 1139 return 1140 pObject != null && 1141 isIntegerType (pObject.getClass ()); 1142 } 1143 1144 //------------------------------------- 1145 /** 1146 * 1147 * Returns true if the given class is of an integer type 1148 **/ 1149 public static boolean isIntegerType (Class pClass) 1150 { 1151 return 1152 pClass == Byte.class || 1153 pClass == Byte.TYPE || 1154 pClass == Short.class || 1155 pClass == Short.TYPE || 1156 pClass == Character.class || 1157 pClass == Character.TYPE || 1158 pClass == Integer.class || 1159 pClass == Integer.TYPE || 1160 pClass == Long.class || 1161 pClass == Long.TYPE; 1162 } 1163 1164 //------------------------------------- 1165 1166 /** 1167 * Returns true if the given object is BigInteger. 1168 * @param pObject - Object to evaluate 1169 * @return - true if the given object is BigInteger 1170 */ 1171 public static boolean isBigInteger(Object pObject) { 1172 return 1173 pObject != null && pObject instanceof BigInteger; 1174 } 1175 1176 /** 1177 * Returns true if the given object is BigDecimal. 1178 * @param pObject - Object to evaluate 1179 * @return - true if the given object is BigDecimal 1180 */ 1181 public static boolean isBigDecimal(Object pObject) { 1182 return 1183 pObject != null && pObject instanceof BigDecimal; 1184 } 1185}