001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements. See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License. You may obtain a copy of the License at
008 *
009 * http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017 package org.apache.commons.el;
018
019 import java.beans.PropertyEditor;
020 import java.beans.PropertyEditorManager;
021 import java.math.BigDecimal;
022 import java.math.BigInteger;
023
024 import javax.servlet.jsp.el.ELException;
025
026 import org.apache.commons.logging.Log;
027 import 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
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 }