View Javadoc

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 public 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 }