Coverage Report - org.apache.commons.el.Coercions
 
Classes in this File Line Coverage Branch Coverage Complexity
Coercions
7%
25/321
6%
37/542
14.682
 
 1  
 /*
 2  
  * Licensed to the Apache Software Foundation (ASF) under one or more
 3  
  * contributor license agreements.  See the NOTICE file distributed with
 4  
  * this work for additional information regarding copyright ownership.
 5  
  * The ASF licenses this file to You under the Apache License, Version 2.0
 6  
  * (the "License"); you may not use this file except in compliance with
 7  
  * the License.  You may obtain a copy of the License at
 8  
  *
 9  
  *     http://www.apache.org/licenses/LICENSE-2.0
 10  
  *
 11  
  * Unless required by applicable law or agreed to in writing, software
 12  
  * distributed under the License is distributed on an "AS IS" BASIS,
 13  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14  
  * See the License for the specific language governing permissions and
 15  
  * limitations under the License.
 16  
  */
 17  
 package org.apache.commons.el;
 18  
 
 19  
 import java.beans.PropertyEditor;
 20  
 import java.beans.PropertyEditorManager;
 21  
 import java.math.BigDecimal;
 22  
 import java.math.BigInteger;
 23  
 
 24  
 import javax.servlet.jsp.el.ELException;
 25  
 
 26  
 import org.apache.commons.logging.Log;
 27  
 import org.apache.commons.logging.LogFactory;
 28  
 
 29  
 /**
 30  
  *
 31  
  * <p>This class contains the logic for coercing data types before
 32  
  * operators are applied to them.
 33  
  *
 34  
  * <p>The following is the list of rules applied for various type
 35  
  * conversions.
 36  
  *
 37  
  * <ul><pre>
 38  
  * Applying arithmetic operator
 39  
  *   Binary operator - A {+,-,*} B
 40  
  *     if A and B are null
 41  
  *       return 0
 42  
  *     if A or B is BigDecimal, coerce both to BigDecimal and then:
 43  
  *       if operator is +, return <code>A.add(B)</code>
 44  
  *       if operator is -, return <code>A.subtract(B)</code>
 45  
  *       if operator is *, return <code>A.multiply(B)</code>
 46  
  *     if A or B is Float, Double, or String containing ".", "e", or "E"
 47  
  *       if A or B is BigInteger, coerce both A and B to BigDecimal and apply operator
 48  
  *       coerce both A and B to Double and apply operator
 49  
  *     if A or B is BigInteger, coerce both to BigInteger and then:
 50  
  *       if operator is +, return <code>A.add(B)</code>
 51  
  *       if operator is -, return <code>A.subtract(B)</code>
 52  
  *       if operator is *, return <code>A.multiply(B)</code>
 53  
  *     otherwise
 54  
  *       coerce both A and B to Long
 55  
  *       apply operator
 56  
  *     if operator results in exception (such as divide by 0), error
 57  
  * 
 58  
  *   Binary operator - A {/,div} B
 59  
  *     if A and B are null
 60  
  *       return 0
 61  
  *     if A or B is a BigDecimal or BigInteger, coerce both to BigDecimal and
 62  
  *      return <code>A.divide(B, BigDecimal.ROUND_HALF_UP)</code>
 63  
  *     otherwise
 64  
  *       coerce both A and B to Double
 65  
  *       apply operator
 66  
  *     if operator results in exception (such as divide by 0), error
 67  
  * 
 68  
  *   Binary operator - A {%,mod} B
 69  
  *     if A and B are null
 70  
  *       return 0
 71  
  *     if A or B is BigDecimal, Float, Double, or String containing ".", "e" or "E"
 72  
  *       coerce both to Double
 73  
  *       apply operator
 74  
  *     if A or B is BigInteger, coerce both to BigInteger and return
 75  
  *      <code>A.remainder(B)</code>
 76  
  *     otherwise
 77  
  *       coerce both A and B to Long
 78  
  *       apply operator
 79  
  *     if operator results in exception (such as divide by 0), error
 80  
  * 
 81  
  *   Unary minus operator - -A
 82  
  *     if A is null
 83  
  *       return 0
 84  
  *     if A is BigInteger or BigDecimal, return <code>A.negate()</code>
 85  
  *     if A is String
 86  
  *       if A contains ".", "e", or "E"
 87  
  *         coerce to Double, apply operator
 88  
  *       otherwise
 89  
  *         coerce to a Long and apply operator
 90  
  *     if A is Byte,Short,Integer,Long,Float,Double
 91  
  *       retain type, apply operator
 92  
  *     if operator results in exception, error
 93  
  *     otherwise
 94  
  *       error
 95  
  *
 96  
  * Applying "empty" operator - empty A
 97  
  *   if A is null
 98  
  *     return true
 99  
  *   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  
 
 280  0
 public class Coercions
 281  
 {
 282  
     //-------------------------------------
 283  
     // Constants
 284  
     //-------------------------------------
 285  1
    private static final Number ZERO = new Integer(0);
 286  6
     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  9
     if (pClass == String.class) {
 298  9
       return coerceToString (pValue);
 299  
     }
 300  0
     else if (isNumberClass (pClass)) {
 301  0
       return coerceToPrimitiveNumber (pValue, pClass);
 302  
     }
 303  0
     else if (pClass == Character.class ||
 304  
              pClass == Character.TYPE) {
 305  0
       return coerceToCharacter (pValue);
 306  
     }
 307  0
     else if (pClass == Boolean.class ||
 308  
              pClass == Boolean.TYPE) {
 309  0
       return coerceToBoolean (pValue);
 310  
     }
 311  
     else {
 312  0
       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  0
     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  9
     if (pValue == null) {
 350  0
       return "";
 351  
     }
 352  9
     else if (pValue instanceof String) {
 353  9
       return (String) pValue;
 354  
     }
 355  
     else {
 356  
       try {
 357  0
         return pValue.toString ();
 358  
       }
 359  0
       catch (Exception exc) {          
 360  0
           if (log.isErrorEnabled()) {
 361  0
               String message = MessageUtil.getMessageWithArgs(
 362  
                   Constants.TOSTRING_EXCEPTION,
 363  
                   pValue.getClass().getName());
 364  0
               log.error(message, exc);
 365  0
               throw new ELException(exc);
 366  
           }
 367  0
           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  4
     if (pValue == null ||
 382  
         "".equals (pValue)) {
 383  0
       return coerceToPrimitiveNumber (ZERO, pClass);
 384  
     }
 385  4
     else if (pValue instanceof Character) {
 386  0
       char val = ((Character) pValue).charValue ();
 387  0
       return coerceToPrimitiveNumber (new Short((short) val), pClass);
 388  
     }
 389  4
     else if (pValue instanceof Boolean) {
 390  0
         if (log.isErrorEnabled()) {
 391  0
             String message = MessageUtil.getMessageWithArgs(
 392  
                 Constants.BOOLEAN_TO_NUMBER, pValue, pClass.getName());
 393  0
             log.error(message);
 394  0
             throw new ELException(message);
 395  
         }
 396  0
         return coerceToPrimitiveNumber(ZERO, pClass);     
 397  
     }
 398  4
     else if (pValue.getClass () == pClass) {
 399  4
       return (Number) pValue;
 400  
     }
 401  0
     else if (pValue instanceof Number) {
 402  0
       return coerceToPrimitiveNumber ((Number) pValue, pClass);
 403  
     }
 404  0
     else if (pValue instanceof String) {
 405  
       try {
 406  0
         return coerceToPrimitiveNumber ((String) pValue, pClass);
 407  
       }
 408  0
       catch (Exception exc) {
 409  0
           if (log.isErrorEnabled()) {
 410  0
               String message = MessageUtil.getMessageWithArgs(
 411  
                   Constants.STRING_TO_NUMBER_EXCEPTION,
 412  
                   (String) pValue, pClass.getName());
 413  0
               log.error(message);
 414  0
               throw new ELException(message);
 415  
           }        
 416  0
             return coerceToPrimitiveNumber (ZERO, pClass);
 417  
       }
 418  
     }
 419  
     else {
 420  0
         if (log.isErrorEnabled()) {
 421  0
             String message = MessageUtil.getMessageWithArgs(
 422  
                 Constants.COERCE_TO_NUMBER,
 423  
                 pValue.getClass().getName(),
 424  
                 pClass.getName());
 425  0
             log.error(message);
 426  0
             throw new ELException(message);
 427  
         }      
 428  0
       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  0
     if (pValue == null) {
 442  0
       return null;
 443  
     }
 444  0
     else if (pValue instanceof Character) {
 445  0
       return PrimitiveObjects.getInteger 
 446  
         ((int) (((Character) pValue).charValue ()));
 447  
     }
 448  0
     else if (pValue instanceof Boolean) {
 449  0
         if (log.isWarnEnabled()) {
 450  0
             log.warn(
 451  
                 MessageUtil.getMessageWithArgs(
 452  
                     Constants.BOOLEAN_TO_NUMBER, pValue, Integer.class.getName()));            
 453  
         }     
 454  0
       return PrimitiveObjects.getInteger
 455  
         (((Boolean) pValue).booleanValue () ? 1 : 0);
 456  
     }
 457  0
     else if (pValue instanceof Integer) {
 458  0
       return (Integer) pValue;
 459  
     }
 460  0
     else if (pValue instanceof Number) {
 461  0
       return PrimitiveObjects.getInteger (((Number) pValue).intValue ());
 462  
     }
 463  0
     else if (pValue instanceof String) {
 464  
       try {
 465  0
         return Integer.valueOf ((String) pValue);
 466  
       }
 467  0
       catch (Exception exc) {
 468  0
           if (log.isWarnEnabled()) {
 469  0
               log.warn(
 470  
                   MessageUtil.getMessageWithArgs(
 471  
                       Constants.STRING_TO_NUMBER_EXCEPTION,
 472  
                       (String) pValue,
 473  
                       Integer.class.getName()));            
 474  
           }        
 475  0
         return null;
 476  
       }
 477  
     }
 478  
     else {
 479  0
         if (log.isWarnEnabled()) {
 480  0
             log.warn(
 481  
                 MessageUtil.getMessageWithArgs(
 482  
                     Constants.COERCE_TO_NUMBER,
 483  
                     pValue.getClass().getName(),
 484  
                     Integer.class.getName()));
 485  
         }
 486  0
       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  0
     if (pClass == Byte.class || pClass == Byte.TYPE) {
 500  0
       return PrimitiveObjects.getByte ((byte) pValue);
 501  
     }
 502  0
     else if (pClass == Short.class || pClass == Short.TYPE) {
 503  0
       return PrimitiveObjects.getShort ((short) pValue);
 504  
     }
 505  0
     else if (pClass == Integer.class || pClass == Integer.TYPE) {
 506  0
       return PrimitiveObjects.getInteger ((int) pValue);
 507  
     }
 508  0
     else if (pClass == Long.class || pClass == Long.TYPE) {
 509  0
       return PrimitiveObjects.getLong (pValue);
 510  
     }
 511  0
     else if (pClass == Float.class || pClass == Float.TYPE) {
 512  0
       return PrimitiveObjects.getFloat ((float) pValue);
 513  
     }
 514  0
     else if (pClass == Double.class || pClass == Double.TYPE) {
 515  0
       return PrimitiveObjects.getDouble ((double) pValue);
 516  
     }
 517  
     else {
 518  0
       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  0
     if (pClass == Byte.class || pClass == Byte.TYPE) {
 532  0
       return PrimitiveObjects.getByte ((byte) pValue);
 533  
     }
 534  0
     else if (pClass == Short.class || pClass == Short.TYPE) {
 535  0
       return PrimitiveObjects.getShort ((short) pValue);
 536  
     }
 537  0
     else if (pClass == Integer.class || pClass == Integer.TYPE) {
 538  0
       return PrimitiveObjects.getInteger ((int) pValue);
 539  
     }
 540  0
     else if (pClass == Long.class || pClass == Long.TYPE) {
 541  0
       return PrimitiveObjects.getLong ((long) pValue);
 542  
     }
 543  0
     else if (pClass == Float.class || pClass == Float.TYPE) {
 544  0
       return PrimitiveObjects.getFloat ((float) pValue);
 545  
     }
 546  0
     else if (pClass == Double.class || pClass == Double.TYPE) {
 547  0
       return PrimitiveObjects.getDouble (pValue);
 548  
     }
 549  
     else {
 550  0
       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  0
     if (pClass == Byte.class || pClass == Byte.TYPE) {
 563  0
       return PrimitiveObjects.getByte (pValue.byteValue ());
 564  
     }
 565  0
     else if (pClass == Short.class || pClass == Short.TYPE) {
 566  0
       return PrimitiveObjects.getShort (pValue.shortValue ());
 567  
     }
 568  0
     else if (pClass == Integer.class || pClass == Integer.TYPE) {
 569  0
       return PrimitiveObjects.getInteger (pValue.intValue ());
 570  
     }
 571  0
     else if (pClass == Long.class || pClass == Long.TYPE) {
 572  0
       return PrimitiveObjects.getLong (pValue.longValue ());
 573  
     }
 574  0
     else if (pClass == Float.class || pClass == Float.TYPE) {
 575  0
       return PrimitiveObjects.getFloat (pValue.floatValue ());
 576  
     }
 577  0
     else if (pClass == Double.class || pClass == Double.TYPE) {
 578  0
       return PrimitiveObjects.getDouble (pValue.doubleValue ());
 579  
     }
 580  0
     else if (pClass == BigInteger.class) {
 581  0
         if (pValue instanceof BigDecimal)
 582  0
             return ((BigDecimal) pValue).toBigInteger();
 583  
         else
 584  0
             return BigInteger.valueOf(pValue.longValue());
 585  
     }
 586  0
     else if (pClass == BigDecimal.class) {
 587  0
         if (pValue instanceof BigInteger)
 588  0
             return new BigDecimal((BigInteger) pValue);
 589  
         else
 590  0
             return new BigDecimal(pValue.doubleValue());
 591  
     }
 592  
     else {
 593  0
       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  0
     if (pClass == Byte.class || pClass == Byte.TYPE) {
 606  0
       return Byte.valueOf (pValue);
 607  
     }
 608  0
     else if (pClass == Short.class || pClass == Short.TYPE) {
 609  0
       return Short.valueOf (pValue);
 610  
     }
 611  0
     else if (pClass == Integer.class || pClass == Integer.TYPE) {
 612  0
       return Integer.valueOf (pValue);
 613  
     }
 614  0
     else if (pClass == Long.class || pClass == Long.TYPE) {
 615  0
       return Long.valueOf (pValue);
 616  
     }
 617  0
     else if (pClass == Float.class || pClass == Float.TYPE) {
 618  0
       return Float.valueOf (pValue);
 619  
     }
 620  0
     else if (pClass == Double.class || pClass == Double.TYPE) {
 621  0
       return Double.valueOf (pValue);
 622  
     }
 623  0
     else if (pClass == BigInteger.class) {
 624  0
         return new BigInteger(pValue);
 625  
     }
 626  0
     else if (pClass == BigDecimal.class) {
 627  0
         return new BigDecimal(pValue);
 628  
     }
 629  
     else {
 630  0
       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  0
     if (pValue == null ||
 643  
         "".equals (pValue)) {
 644  0
       return PrimitiveObjects.getCharacter ((char) 0);
 645  
     }
 646  0
     else if (pValue instanceof Character) {
 647  0
       return (Character) pValue;
 648  
     }
 649  0
     else if (pValue instanceof Boolean) {
 650  0
         if (log.isErrorEnabled()) {
 651  0
             String message = MessageUtil.getMessageWithArgs(
 652  
                 Constants.BOOLEAN_TO_CHARACTER, pValue);
 653  0
             log.error(message);
 654  0
             throw new ELException(message);
 655  
         }     
 656  0
       return PrimitiveObjects.getCharacter ((char) 0);
 657  
     }
 658  0
     else if (pValue instanceof Number) {
 659  0
       return PrimitiveObjects.getCharacter 
 660  
         ((char) ((Number) pValue).shortValue ());
 661  
     }
 662  0
     else if (pValue instanceof String) {
 663  0
       String str = (String) pValue;
 664  0
       return PrimitiveObjects.getCharacter (str.charAt (0));
 665  
     }
 666  
     else {
 667  0
         if (log.isErrorEnabled()) {
 668  0
             String message = MessageUtil.getMessageWithArgs(
 669  
                 Constants.COERCE_TO_CHARACTER,
 670  
                 pValue.getClass().getName());
 671  0
             log.error(message);
 672  0
             throw new ELException(message);
 673  
         }     
 674  0
       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  0
     if (pValue == null ||
 687  
         "".equals (pValue)) {
 688  0
       return Boolean.FALSE;
 689  
     }
 690  0
     else if (pValue instanceof Boolean) {
 691  0
       return (Boolean) pValue;
 692  
     }
 693  0
     else if (pValue instanceof String) {
 694  0
       String str = (String) pValue;
 695  
       try {
 696  0
         return Boolean.valueOf (str);
 697  
       }
 698  0
       catch (Exception exc) {
 699  0
           if (log.isErrorEnabled()) {
 700  0
               String message = MessageUtil.getMessageWithArgs(
 701  
                   Constants.STRING_TO_BOOLEAN, (String) pValue);
 702  0
               log.error(message, exc);
 703  0
               throw new ELException(message, exc);
 704  
           }        
 705  0
         return Boolean.FALSE;
 706  
       }
 707  
     }
 708  
     else {
 709  0
         if (log.isErrorEnabled()) {
 710  0
             String message = MessageUtil.getMessageWithArgs(
 711  
                 Constants.COERCE_TO_BOOLEAN,
 712  
                 pValue.getClass().getName());
 713  0
             log.error(message);
 714  0
             throw new ELException(message);
 715  
         }     
 716  0
       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  0
     if (pValue == null) {
 730  0
       return null;
 731  
     }
 732  0
     else if (pClass.isAssignableFrom (pValue.getClass ())) {
 733  0
       return pValue;
 734  
     }
 735  0
     else if (pValue instanceof String) {
 736  0
       String str = (String) pValue;
 737  0
       PropertyEditor pe = PropertyEditorManager.findEditor (pClass);
 738  0
       if (pe == null) {
 739  0
         if ("".equals (str)) {
 740  0
           return null;
 741  
         }
 742  
         else {
 743  0
         if (log.isErrorEnabled()) {
 744  0
             String message = MessageUtil.getMessageWithArgs(
 745  
                 Constants.NO_PROPERTY_EDITOR,
 746  
                 str, pClass.getName());
 747  0
             log.error(message);
 748  0
             throw new ELException(message);
 749  
         }          
 750  0
           return null;
 751  
         }
 752  
       }
 753  
       try {
 754  0
         pe.setAsText (str);
 755  0
         return pe.getValue ();
 756  
       }
 757  0
       catch (IllegalArgumentException exc) {
 758  0
         if ("".equals (str)) {
 759  0
           return null;
 760  
         }
 761  
         else {
 762  0
         if (log.isErrorEnabled()) {
 763  0
             String message = MessageUtil.getMessageWithArgs(
 764  
                 Constants.PROPERTY_EDITOR_ERROR,
 765  
                 pValue,
 766  
                 pClass.getName());
 767  0
             log.error(message, exc);
 768  0
             throw new ELException(message, exc);
 769  
         }          
 770  0
           return null;
 771  
         }
 772  
       }
 773  
     }
 774  
     else {
 775  0
         if (log.isErrorEnabled()) {
 776  0
             String message = MessageUtil.getMessageWithArgs(
 777  
                 Constants.COERCE_TO_OBJECT,
 778  
                 pValue.getClass().getName(),
 779  
                 pClass.getName());
 780  0
             log.error(message);
 781  0
             throw new ELException(message);
 782  
         }     
 783  0
       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  2
     if (pLeft == null &&
 802  
         pRight == null) {
 803  0
         if (log.isWarnEnabled()) {
 804  0
             log.warn(
 805  
                 MessageUtil.getMessageWithArgs(
 806  
                     Constants.ARITH_OP_NULL,
 807  
                     pOperator.getOperatorSymbol()));
 808  
         }    
 809  0
       return PrimitiveObjects.getInteger (0);
 810  
     }
 811  
 
 812  2
     else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
 813  0
         BigDecimal left = (BigDecimal)
 814  
             coerceToPrimitiveNumber(pLeft, BigDecimal.class);
 815  0
         BigDecimal right = (BigDecimal)
 816  
             coerceToPrimitiveNumber(pRight, BigDecimal.class);
 817  0
         return pOperator.apply(left, right);
 818  
     }
 819  
 
 820  2
     else if (isFloatingPointType(pLeft) ||
 821  
         isFloatingPointType(pRight) ||
 822  
         isFloatingPointString(pLeft) ||
 823  
         isFloatingPointString(pRight)) {
 824  0
         if (isBigInteger(pLeft) || isBigInteger(pRight)) {
 825  0
             BigDecimal left = (BigDecimal)
 826  
                 coerceToPrimitiveNumber(pLeft, BigDecimal.class);
 827  0
             BigDecimal right = (BigDecimal)
 828  
                 coerceToPrimitiveNumber(pRight, BigDecimal.class);
 829  0
             return pOperator.apply(left, right);
 830  
         } else {
 831  0
             double left =
 832  
                 coerceToPrimitiveNumber(pLeft, Double.class).
 833  
                 doubleValue();
 834  0
             double right =
 835  
                 coerceToPrimitiveNumber(pRight, Double.class).
 836  
                 doubleValue();
 837  0
             return
 838  
                 PrimitiveObjects.getDouble(pOperator.apply(left, right));
 839  
         }
 840  
     }
 841  
 
 842  2
     else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
 843  0
         BigInteger left = (BigInteger)
 844  
             coerceToPrimitiveNumber(pLeft, BigInteger.class);
 845  0
         BigInteger right = (BigInteger)
 846  
             coerceToPrimitiveNumber(pRight, BigInteger.class);
 847  0
         return pOperator.apply(left, right);
 848  
     }
 849  
 
 850  
     else {
 851  2
       long left =
 852  
         coerceToPrimitiveNumber (pLeft, Long.class).
 853  
         longValue ();
 854  2
       long right =
 855  
         coerceToPrimitiveNumber (pRight, Long.class).
 856  
         longValue ();
 857  2
       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  0
     if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
 875  0
         BigDecimal left = (BigDecimal)
 876  
             coerceToPrimitiveNumber(pLeft, BigDecimal.class);
 877  0
         BigDecimal right = (BigDecimal)
 878  
             coerceToPrimitiveNumber(pRight, BigDecimal.class);
 879  0
         return PrimitiveObjects.getBoolean(pOperator.apply(left, right));
 880  
     }
 881  
 
 882  0
     else if (isFloatingPointType (pLeft) ||
 883  
         isFloatingPointType (pRight)) {
 884  0
       double left =
 885  
         coerceToPrimitiveNumber (pLeft, Double.class).
 886  
         doubleValue ();
 887  0
       double right =
 888  
         coerceToPrimitiveNumber (pRight, Double.class).
 889  
         doubleValue ();
 890  0
       return 
 891  
         PrimitiveObjects.getBoolean (pOperator.apply (left, right));
 892  
     }
 893  
 
 894  0
     else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
 895  0
         BigInteger left = (BigInteger)
 896  
             coerceToPrimitiveNumber(pLeft, BigInteger.class);
 897  0
         BigInteger right = (BigInteger)
 898  
             coerceToPrimitiveNumber(pRight, BigInteger.class);
 899  0
         return PrimitiveObjects.getBoolean(pOperator.apply(left, right));
 900  
     }
 901  
 
 902  0
     else if (isIntegerType (pLeft) ||
 903  
              isIntegerType (pRight)) {
 904  0
       long left =
 905  
         coerceToPrimitiveNumber (pLeft, Long.class).
 906  
         longValue ();
 907  0
       long right =
 908  
         coerceToPrimitiveNumber (pRight, Long.class).
 909  
         longValue ();
 910  0
       return
 911  
         PrimitiveObjects.getBoolean (pOperator.apply (left, right));
 912  
     }
 913  
 
 914  0
     else if (pLeft instanceof String ||
 915  
              pRight instanceof String) {
 916  0
       String left = coerceToString (pLeft);
 917  0
       String right = coerceToString (pRight);
 918  0
       return
 919  
         PrimitiveObjects.getBoolean (pOperator.apply (left, right));
 920  
     }
 921  
 
 922  0
     else if (pLeft instanceof Comparable) {
 923  
       try {
 924  0
         int result = ((Comparable) pLeft).compareTo (pRight);
 925  0
         return
 926  
           PrimitiveObjects.getBoolean 
 927  
           (pOperator.apply (result, -result));
 928  
       }
 929  0
       catch (Exception exc) {
 930  0
           if (log.isErrorEnabled()) {
 931  0
               String message = MessageUtil.getMessageWithArgs(
 932  
                   Constants.COMPARABLE_ERROR,
 933  
                   pLeft.getClass().getName(),
 934  
                   (pRight == null) ? "null" : pRight.getClass().getName(),
 935  
                   pOperator.getOperatorSymbol());
 936  0
               log.error(message, exc);
 937  0
               throw new ELException(message, exc);
 938  
           }        
 939  0
         return Boolean.FALSE;
 940  
       }
 941  
     }
 942  
 
 943  0
     else if (pRight instanceof Comparable) {
 944  
       try {
 945  0
         int result = ((Comparable) pRight).compareTo (pLeft);
 946  0
         return
 947  
           PrimitiveObjects.getBoolean 
 948  
           (pOperator.apply (-result, result));
 949  
       }
 950  0
       catch (Exception exc) {
 951  0
           if (log.isErrorEnabled()) {
 952  0
               String message = MessageUtil.getMessageWithArgs(
 953  
                   Constants.COMPARABLE_ERROR,
 954  
                   pRight.getClass().getName(),
 955  
                   (pLeft == null) ? "null" : pLeft.getClass().getName(),
 956  
                   pOperator.getOperatorSymbol());
 957  0
               log.error(message, exc);
 958  0
               throw new ELException(message, exc);
 959  
           }                
 960  0
         return Boolean.FALSE;
 961  
       }
 962  
     }
 963  
 
 964  
     else {
 965  0
         if (log.isErrorEnabled()) {
 966  0
             String message = MessageUtil.getMessageWithArgs(
 967  
                 Constants.ARITH_OP_BAD_TYPE,
 968  
                 pOperator.getOperatorSymbol(),
 969  
                 pLeft.getClass().getName(),
 970  
                 pRight.getClass().getName());
 971  0
             log.error(message);
 972  0
             throw new ELException(message);
 973  
         }     
 974  0
       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  0
     if (pLeft == pRight) {
 991  0
       return PrimitiveObjects.getBoolean (pOperator.apply (true));
 992  
     }
 993  
 
 994  0
     else if (pLeft == null ||
 995  
              pRight == null) {
 996  0
       return PrimitiveObjects.getBoolean (pOperator.apply (false));
 997  
     }
 998  
 
 999  0
     else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
 1000  0
         BigDecimal left = (BigDecimal)
 1001  
             coerceToPrimitiveNumber(pLeft, BigDecimal.class);
 1002  0
         BigDecimal right = (BigDecimal)
 1003  
             coerceToPrimitiveNumber(pRight, BigDecimal.class);
 1004  0
         return PrimitiveObjects.getBoolean(pOperator.apply(left.equals(right)));
 1005  
     }
 1006  
 
 1007  0
     else if (isFloatingPointType (pLeft) ||
 1008  
              isFloatingPointType (pRight)) {
 1009  0
       double left =
 1010  
         coerceToPrimitiveNumber (pLeft, Double.class).
 1011  
         doubleValue ();
 1012  0
       double right =
 1013  
         coerceToPrimitiveNumber (pRight, Double.class).
 1014  
         doubleValue ();
 1015  0
       return 
 1016  
         PrimitiveObjects.getBoolean 
 1017  
         (pOperator.apply (left == right));
 1018  
     }
 1019  
 
 1020  0
     else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
 1021  0
         BigInteger left = (BigInteger)
 1022  
             coerceToPrimitiveNumber(pLeft, BigInteger.class);
 1023  0
         BigInteger right = (BigInteger)
 1024  
             coerceToPrimitiveNumber(pRight, BigInteger.class);
 1025  0
         return PrimitiveObjects.getBoolean(pOperator.apply(left.equals(right)));
 1026  
     }
 1027  
 
 1028  0
     else if (isIntegerType (pLeft) ||
 1029  
              isIntegerType (pRight)) {
 1030  0
       long left =
 1031  
         coerceToPrimitiveNumber (pLeft, Long.class).
 1032  
         longValue ();
 1033  0
       long right =
 1034  
         coerceToPrimitiveNumber (pRight, Long.class).
 1035  
         longValue ();
 1036  0
       return
 1037  
         PrimitiveObjects.getBoolean 
 1038  
         (pOperator.apply (left == right));
 1039  
     }
 1040  
 
 1041  0
     else if (pLeft instanceof Boolean ||
 1042  
              pRight instanceof Boolean) {
 1043  0
       boolean left = coerceToBoolean (pLeft).booleanValue ();
 1044  0
       boolean right = coerceToBoolean (pRight).booleanValue ();
 1045  0
       return
 1046  
         PrimitiveObjects.getBoolean 
 1047  
         (pOperator.apply (left == right));
 1048  
     }
 1049  
 
 1050  0
     else if (pLeft instanceof String ||
 1051  
              pRight instanceof String) {
 1052  0
       String left = coerceToString (pLeft);
 1053  0
       String right = coerceToString (pRight);
 1054  0
       return
 1055  
         PrimitiveObjects.getBoolean 
 1056  
         (pOperator.apply (left.equals (right)));
 1057  
     }
 1058  
 
 1059  
     else {
 1060  
       try {
 1061  0
       return
 1062  
         PrimitiveObjects.getBoolean
 1063  
         (pOperator.apply (pLeft.equals (pRight)));
 1064  
       }
 1065  0
       catch (Exception exc) {
 1066  0
           if (log.isErrorEnabled()) {
 1067  0
               String message = MessageUtil.getMessageWithArgs(
 1068  
                   Constants.ERROR_IN_EQUALS,
 1069  
                   pLeft.getClass().getName(),
 1070  
                   pRight.getClass().getName(),
 1071  
                   pOperator.getOperatorSymbol());
 1072  0
               log.error(message, exc);
 1073  0
               throw new ELException(message, exc);
 1074  
           }        
 1075  0
         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  4
     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  4
     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  4
     if (pObject instanceof String) {
 1115  0
       String str = (String) pObject;
 1116  0
       int len = str.length ();
 1117  0
       for (int i = 0; i < len; i++) {
 1118  0
         char ch = str.charAt (i);
 1119  0
         if (ch == '.' ||
 1120  
             ch == 'e' ||
 1121  
             ch == 'E') {
 1122  0
           return true;
 1123  
         }
 1124  
       }
 1125  0
       return false;
 1126  
     }
 1127  
     else {
 1128  4
       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  0
     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  0
     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  4
       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  4
       return
 1183  
           pObject != null && pObject instanceof BigDecimal;
 1184  
   }
 1185  
 }