Source code: org/apache/commons/el/Coercions.java
1 /*
2 * The Apache Software License, Version 1.1
3 *
4 * Copyright (c) 1999 The Apache Software Foundation. All rights
5 * reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * 3. The end-user documentation included with the redistribution, if
20 * any, must include the following acknowlegement:
21 * "This product includes software developed by the
22 * Apache Software Foundation (http://www.apache.org/)."
23 * Alternately, this acknowlegement may appear in the software itself,
24 * if and wherever such third-party acknowlegements normally appear.
25 *
26 * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
27 * Foundation" must not be used to endorse or promote products derived
28 * from this software without prior written permission. For written
29 * permission, please contact apache@apache.org.
30 *
31 * 5. Products derived from this software may not be called "Apache"
32 * nor may "Apache" appear in their names without prior written
33 * permission of the Apache Group.
34 *
35 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46 * SUCH DAMAGE.
47 * ====================================================================
48 *
49 * This software consists of voluntary contributions made by many
50 * individuals on behalf of the Apache Software Foundation. For more
51 * information on the Apache Software Foundation, please see
52 * <http://www.apache.org/>.
53 *
54 */
55
56 package org.apache.commons.el;
57
58 import java.beans.PropertyEditor;
59 import java.beans.PropertyEditorManager;
60 import java.math.BigInteger;
61 import java.math.BigDecimal;
62 import javax.servlet.jsp.el.ELException;
63
64 /**
65 *
66 * <p>This class contains the logic for coercing data types before
67 * operators are applied to them.
68 *
69 * <p>The following is the list of rules applied for various type
70 * conversions.
71 *
72 * <ul><pre>
73 * Applying arithmetic operator
74 * Binary operator - A {+,-,*} B
75 * if A and B are null
76 * return 0
77 * if A or B is BigDecimal, coerce both to BigDecimal and then:
78 * if operator is +, return <code>A.add(B)</code>
79 * if operator is -, return <code>A.subtract(B)</code>
80 * if operator is *, return <code>A.multiply(B)</code>
81 * if A or B is Float, Double, or String containing ".", "e", or "E"
82 * if A or B is BigInteger, coerce both A and B to BigDecimal and apply operator
83 * coerce both A and B to Double and apply operator
84 * if A or B is BigInteger, coerce both to BigInteger and then:
85 * if operator is +, return <code>A.add(B)</code>
86 * if operator is -, return <code>A.subtract(B)</code>
87 * if operator is *, return <code>A.multiply(B)</code>
88 * otherwise
89 * coerce both A and B to Long
90 * apply operator
91 * if operator results in exception (such as divide by 0), error
92 *
93 * Binary operator - A {/,div} B
94 * if A and B are null
95 * return 0
96 * if A or B is a BigDecimal or BigInteger, coerce both to BigDecimal and
97 * return <code>A.divide(B, BigDecimal.ROUND_HALF_UP)</code>
98 * otherwise
99 * coerce both A and B to Double
100 * apply operator
101 * if operator results in exception (such as divide by 0), error
102 *
103 * Binary operator - A {%,mod} B
104 * if A and B are null
105 * return 0
106 * if A or B is BigDecimal, Float, Double, or String containing ".", "e" or "E"
107 * coerce both to Double
108 * apply operator
109 * if A or B is BigInteger, coerce both to BigInteger and return
110 * <code>A.remainder(B)</code>
111 * otherwise
112 * coerce both A and B to Long
113 * apply operator
114 * if operator results in exception (such as divide by 0), error
115 *
116 * Unary minus operator - -A
117 * if A is null
118 * return 0
119 * if A is BigInteger or BigDecimal, return <code>A.negate()</code>
120 * if A is String
121 * if A contains ".", "e", or "E"
122 * coerce to Double, apply operator
123 * otherwise
124 * coerce to a Long and apply operator
125 * if A is Byte,Short,Integer,Long,Float,Double
126 * retain type, apply operator
127 * if operator results in exception, error
128 * otherwise
129 * error
130 *
131 * Applying "empty" operator - empty A
132 * if A is null
133 * return true
134 * if A is zero-length String
135 * return true
136 * if A is zero-length array
137 * return true
138 * if A is List and ((List) A).isEmpty()
139 * return true
140 * if A is Map and ((Map) A).isEmpty()
141 * return true
142 * if A is Collection an ((Collection) A).isEmpty()
143 * return true
144 * otherwise
145 * return false
146 *
147 * Applying logical operators
148 * Binary operator - A {and,or} B
149 * coerce both A and B to Boolean, apply operator
150 * NOTE - operator stops as soon as expression can be determined, i.e.,
151 * A and B and C and D - if B is false, then only A and B is evaluated
152 * Unary not operator - not A
153 * coerce A to Boolean, apply operator
154 *
155 * Applying relational operator
156 * A {<,>,<=,>=,lt,gt,lte,gte} B
157 * if A==B
158 * if operator is >= or <=
159 * return true
160 * otherwise
161 * return false
162 * if A or B is null
163 * return false
164 * if A or B is BigDecimal, coerce both A and B to BigDecimal and use the
165 * return value of <code>A.compareTo(B)</code>
166 * if A or B is Float or Double
167 * coerce both A and B to Double
168 * apply operator
169 * if A or B is BigInteger, coerce both A and B to BigInteger and use the
170 * return value of <code>A.compareTo(B)</code>
171 * if A or B is Byte,Short,Character,Integer,Long
172 * coerce both A and B to Long
173 * apply operator
174 * if A or B is String
175 * coerce both A and B to String, compare lexically
176 * if A is Comparable
177 * if A.compareTo (B) throws exception
178 * error
179 * otherwise
180 * use result of A.compareTo(B)
181 * if B is Comparable
182 * if B.compareTo (A) throws exception
183 * error
184 * otherwise
185 * use result of B.compareTo(A)
186 * otherwise
187 * error
188 *
189 * Applying equality operator
190 * A {==,!=} B
191 * if A==B
192 * apply operator
193 * if A or B is null
194 * return false for ==, true for !=
195 * if A or B is BigDecimal, coerce both A and B to BigDecimal and then:
196 * if operator is == or eq, return <code>A.equals(B)</code>
197 * if operator is != or ne, return <code>!A.equals(B)</code>
198 * if A or B is Float or Double
199 * coerce both A and B to Double
200 * apply operator
201 * if A or B is BigInteger, coerce both A and B to BigInteger and then:
202 * if operator is == or eq, return <code>A.equals(B)</code>
203 * if operator is != or ne, return <code>!A.equals(B)</code>
204 * if A or B is Byte,Short,Character,Integer,Long
205 * coerce both A and B to Long
206 * apply operator
207 * if A or B is Boolean
208 * coerce both A and B to Boolean
209 * apply operator
210 * if A or B is String
211 * coerce both A and B to String, compare lexically
212 * otherwise
213 * if an error occurs while calling A.equals(B)
214 * error
215 * apply operator to result of A.equals(B)
216 *
217 * coercions
218 *
219 * coerce A to String
220 * A is String
221 * return A
222 * A is null
223 * return ""
224 * A.toString throws exception
225 * error
226 * otherwise
227 * return A.toString
228 *
229 * coerce A to Number type N
230 * A is null or ""
231 * return 0
232 * A is Character
233 * convert to short, apply following rules
234 * A is Boolean
235 * error
236 * A is Number type N
237 * return A
238 * A is Number, coerce quietly to type N using the following algorithm
239 * If N is BigInteger
240 * If A is BigDecimal, return <code>A.toBigInteger()</code>
241 * Otherwise, return <code>BigInteger.valueOf(A.longValue())</code>
242 * if N is BigDecimal
243 * If A is a BigInteger, return <code>new BigDecimal(A)</code>
244 * Otherwise, return <code>new BigDecimal(A.doubleValue())</code>
245 * If N is Byte, return <code>new Byte(A.byteValue())</code>
246 * If N is Short, return <code>new Short(A.shortValue())</code>
247 * If N is Integer, return <code>new Integer(A.integerValue())</code>
248 * If N is Long, return <code>new Long(A.longValue())</code>
249 * If N is Float, return <code>new Float(A.floatValue())</code>
250 * If N is Double, return <code>new Double(A.doubleValue())</code>
251 * otherwise ERROR
252 * A is String
253 * If N is BigDecimal then:
254 * If <code>new BigDecimal(A)</code> throws an exception then ERROR
255 * Otherwise, return <code>new BigDecimal(A)</code>
256 * If N is BigInteger then:
257 * If <code>new BigInteger(A)</code> throws an exception, then ERROR
258 * Otherwise, return <code>new BigInteger(A)</code>
259 * new <code>N.valueOf(A)</code> throws exception
260 * error
261 * return <code>N.valueOf(A)</code>
262 * otherwise
263 * error
264 *
265 * coerce A to Character should be
266 * A is null or ""
267 * return (char) 0
268 * A is Character
269 * return A
270 * A is Boolean
271 * error
272 * A is Number with less precision than short
273 * coerce quietly - return (char) A
274 * A is Number with greater precision than short
275 * coerce quietly - return (char) A
276 * A is String
277 * return A.charAt (0)
278 * otherwise
279 * error
280 *
281 * coerce A to Boolean
282 * A is null or ""
283 * return false
284 * A is Boolean
285 * return A
286 * A is String
287 * Boolean.valueOf(A) throws exception
288 * error
289 * return Boolean.valueOf(A)
290 * otherwise
291 * error
292 *
293 * coerce A to any other type T
294 * A is null
295 * return null
296 * A is assignable to T
297 * coerce quietly
298 * A is String
299 * T has no PropertyEditor
300 * if A is "", return null
301 * otherwise error
302 * T's PropertyEditor throws exception
303 * if A is "", return null
304 * otherwise error
305 * otherwise
306 * apply T's PropertyEditor
307 * otherwise
308 * error
309 * </pre></ul>
310 *
311 * @author Nathan Abramson - Art Technology Group
312 * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: luehe $
313 **/
314
315 public class Coercions
316 {
317 private static final Number ZERO = new Integer(0);
318 //-------------------------------------
319 /**
320 *
321 * Coerces the given value to the specified class.
322 **/
323 public static Object coerce (Object pValue,
324 Class pClass,
325 Logger pLogger)
326 throws ELException
327 {
328 if (pClass == String.class) {
329 return coerceToString (pValue, pLogger);
330 }
331 else if (isNumberClass (pClass)) {
332 return coerceToPrimitiveNumber (pValue, pClass, pLogger);
333 }
334 else if (pClass == Character.class ||
335 pClass == Character.TYPE) {
336 return coerceToCharacter (pValue, pLogger);
337 }
338 else if (pClass == Boolean.class ||
339 pClass == Boolean.TYPE) {
340 return coerceToBoolean (pValue, pLogger);
341 }
342 else {
343 return coerceToObject (pValue, pClass, pLogger);
344 }
345 }
346
347 //-------------------------------------
348 /**
349 *
350 * Returns true if the given class is Byte, Short, Integer, Long,
351 * Float, Double, BigInteger, or BigDecimal
352 **/
353 static boolean isNumberClass (Class pClass)
354 {
355 return
356 pClass == Byte.class ||
357 pClass == Byte.TYPE ||
358 pClass == Short.class ||
359 pClass == Short.TYPE ||
360 pClass == Integer.class ||
361 pClass == Integer.TYPE ||
362 pClass == Long.class ||
363 pClass == Long.TYPE ||
364 pClass == Float.class ||
365 pClass == Float.TYPE ||
366 pClass == Double.class ||
367 pClass == Double.TYPE ||
368 pClass == BigInteger.class ||
369 pClass == BigDecimal.class;
370 }
371
372 //-------------------------------------
373 /**
374 *
375 * Coerces the specified value to a String
376 **/
377 public static String coerceToString (Object pValue,
378 Logger pLogger)
379 throws ELException
380 {
381 if (pValue == null) {
382 return "";
383 }
384 else if (pValue instanceof String) {
385 return (String) pValue;
386 }
387 else {
388 try {
389 return pValue.toString ();
390 }
391 catch (Exception exc) {
392 if (pLogger.isLoggingError ()) {
393 pLogger.logError (Constants.TOSTRING_EXCEPTION,
394 exc,
395 pValue.getClass ().getName ());
396 }
397 return "";
398 }
399 }
400 }
401
402 //-------------------------------------
403 /**
404 *
405 * Coerces a value to the given primitive number class
406 **/
407 public static Number coerceToPrimitiveNumber (Object pValue,
408 Class pClass,
409 Logger pLogger)
410 throws ELException
411 {
412 if (pValue == null ||
413 "".equals (pValue)) {
414 return coerceToPrimitiveNumber (ZERO, pClass);
415 }
416 else if (pValue instanceof Character) {
417 char val = ((Character) pValue).charValue ();
418 return coerceToPrimitiveNumber (new Short((short) val), pClass);
419 }
420 else if (pValue instanceof Boolean) {
421 if (pLogger.isLoggingError ()) {
422 pLogger.logError (Constants.BOOLEAN_TO_NUMBER,
423 pValue,
424 pClass.getName ());
425 }
426 return coerceToPrimitiveNumber (ZERO, pClass);
427 }
428 else if (pValue.getClass () == pClass) {
429 return (Number) pValue;
430 }
431 else if (pValue instanceof Number) {
432 return coerceToPrimitiveNumber ((Number) pValue, pClass);
433 }
434 else if (pValue instanceof String) {
435 try {
436 return coerceToPrimitiveNumber ((String) pValue, pClass);
437 }
438 catch (Exception exc) {
439 if (pLogger.isLoggingError ()) {
440 pLogger.logError
441 (Constants.STRING_TO_NUMBER_EXCEPTION,
442 (String) pValue,
443 pClass.getName ());
444 }
445 return coerceToPrimitiveNumber (ZERO, pClass);
446 }
447 }
448 else {
449 if (pLogger.isLoggingError ()) {
450 pLogger.logError
451 (Constants.COERCE_TO_NUMBER,
452 pValue.getClass ().getName (),
453 pClass.getName ());
454 }
455 return coerceToPrimitiveNumber (0, pClass);
456 }
457 }
458
459 //-------------------------------------
460 /**
461 *
462 * Coerces a value to an Integer, returning null if the coercion
463 * isn't possible.
464 **/
465 public static Integer coerceToInteger (Object pValue,
466 Logger pLogger)
467 throws ELException
468 {
469 if (pValue == null) {
470 return null;
471 }
472 else if (pValue instanceof Character) {
473 return PrimitiveObjects.getInteger
474 ((int) (((Character) pValue).charValue ()));
475 }
476 else if (pValue instanceof Boolean) {
477 if (pLogger.isLoggingWarning ()) {
478 pLogger.logWarning (Constants.BOOLEAN_TO_NUMBER,
479 pValue,
480 Integer.class.getName ());
481 }
482 return PrimitiveObjects.getInteger
483 (((Boolean) pValue).booleanValue () ? 1 : 0);
484 }
485 else if (pValue instanceof Integer) {
486 return (Integer) pValue;
487 }
488 else if (pValue instanceof Number) {
489 return PrimitiveObjects.getInteger (((Number) pValue).intValue ());
490 }
491 else if (pValue instanceof String) {
492 try {
493 return Integer.valueOf ((String) pValue);
494 }
495 catch (Exception exc) {
496 if (pLogger.isLoggingWarning ()) {
497 pLogger.logWarning
498 (Constants.STRING_TO_NUMBER_EXCEPTION,
499 (String) pValue,
500 Integer.class.getName ());
501 }
502 return null;
503 }
504 }
505 else {
506 if (pLogger.isLoggingWarning ()) {
507 pLogger.logWarning
508 (Constants.COERCE_TO_NUMBER,
509 pValue.getClass ().getName (),
510 Integer.class.getName ());
511 }
512 return null;
513 }
514 }
515
516 //-------------------------------------
517 /**
518 *
519 * Coerces a long to the given primitive number class
520 **/
521 static Number coerceToPrimitiveNumber (long pValue,
522 Class pClass)
523 throws ELException
524 {
525 if (pClass == Byte.class || pClass == Byte.TYPE) {
526 return PrimitiveObjects.getByte ((byte) pValue);
527 }
528 else if (pClass == Short.class || pClass == Short.TYPE) {
529 return PrimitiveObjects.getShort ((short) pValue);
530 }
531 else if (pClass == Integer.class || pClass == Integer.TYPE) {
532 return PrimitiveObjects.getInteger ((int) pValue);
533 }
534 else if (pClass == Long.class || pClass == Long.TYPE) {
535 return PrimitiveObjects.getLong (pValue);
536 }
537 else if (pClass == Float.class || pClass == Float.TYPE) {
538 return PrimitiveObjects.getFloat ((float) pValue);
539 }
540 else if (pClass == Double.class || pClass == Double.TYPE) {
541 return PrimitiveObjects.getDouble ((double) pValue);
542 }
543 else {
544 return PrimitiveObjects.getInteger (0);
545 }
546 }
547
548 //-------------------------------------
549 /**
550 *
551 * Coerces a double to the given primitive number class
552 **/
553 static Number coerceToPrimitiveNumber (double pValue,
554 Class pClass)
555 throws ELException
556 {
557 if (pClass == Byte.class || pClass == Byte.TYPE) {
558 return PrimitiveObjects.getByte ((byte) pValue);
559 }
560 else if (pClass == Short.class || pClass == Short.TYPE) {
561 return PrimitiveObjects.getShort ((short) pValue);
562 }
563 else if (pClass == Integer.class || pClass == Integer.TYPE) {
564 return PrimitiveObjects.getInteger ((int) pValue);
565 }
566 else if (pClass == Long.class || pClass == Long.TYPE) {
567 return PrimitiveObjects.getLong ((long) pValue);
568 }
569 else if (pClass == Float.class || pClass == Float.TYPE) {
570 return PrimitiveObjects.getFloat ((float) pValue);
571 }
572 else if (pClass == Double.class || pClass == Double.TYPE) {
573 return PrimitiveObjects.getDouble (pValue);
574 }
575 else {
576 return PrimitiveObjects.getInteger (0);
577 }
578 }
579
580 //-------------------------------------
581 /**
582 *
583 * Coerces a Number to the given primitive number class
584 **/
585 static Number coerceToPrimitiveNumber (Number pValue,
586 Class pClass)
587 throws ELException
588 {
589 if (pClass == Byte.class || pClass == Byte.TYPE) {
590 return PrimitiveObjects.getByte (pValue.byteValue ());
591 }
592 else if (pClass == Short.class || pClass == Short.TYPE) {
593 return PrimitiveObjects.getShort (pValue.shortValue ());
594 }
595 else if (pClass == Integer.class || pClass == Integer.TYPE) {
596 return PrimitiveObjects.getInteger (pValue.intValue ());
597 }
598 else if (pClass == Long.class || pClass == Long.TYPE) {
599 return PrimitiveObjects.getLong (pValue.longValue ());
600 }
601 else if (pClass == Float.class || pClass == Float.TYPE) {
602 return PrimitiveObjects.getFloat (pValue.floatValue ());
603 }
604 else if (pClass == Double.class || pClass == Double.TYPE) {
605 return PrimitiveObjects.getDouble (pValue.doubleValue ());
606 }
607 else if (pClass == BigInteger.class) {
608 if (pValue instanceof BigDecimal)
609 return ((BigDecimal) pValue).toBigInteger();
610 else
611 return BigInteger.valueOf(pValue.longValue());
612 }
613 else if (pClass == BigDecimal.class) {
614 if (pValue instanceof BigInteger)
615 return new BigDecimal((BigInteger) pValue);
616 else
617 return new BigDecimal(pValue.doubleValue());
618 }
619 else {
620 return PrimitiveObjects.getInteger (0);
621 }
622 }
623
624 //-------------------------------------
625 /**
626 *
627 * Coerces a String to the given primitive number class
628 **/
629 static Number coerceToPrimitiveNumber (String pValue,
630 Class pClass)
631 throws ELException
632 {
633 if (pClass == Byte.class || pClass == Byte.TYPE) {
634 return Byte.valueOf (pValue);
635 }
636 else if (pClass == Short.class || pClass == Short.TYPE) {
637 return Short.valueOf (pValue);
638 }
639 else if (pClass == Integer.class || pClass == Integer.TYPE) {
640 return Integer.valueOf (pValue);
641 }
642 else if (pClass == Long.class || pClass == Long.TYPE) {
643 return Long.valueOf (pValue);
644 }
645 else if (pClass == Float.class || pClass == Float.TYPE) {
646 return Float.valueOf (pValue);
647 }
648 else if (pClass == Double.class || pClass == Double.TYPE) {
649 return Double.valueOf (pValue);
650 }
651 else if (pClass == BigInteger.class) {
652 return new BigInteger(pValue);
653 }
654 else if (pClass == BigDecimal.class) {
655 return new BigDecimal(pValue);
656 }
657 else {
658 return PrimitiveObjects.getInteger (0);
659 }
660 }
661
662 //-------------------------------------
663 /**
664 *
665 * Coerces a value to a Character
666 **/
667 public static Character coerceToCharacter (Object pValue,
668 Logger pLogger)
669 throws ELException
670 {
671 if (pValue == null ||
672 "".equals (pValue)) {
673 return PrimitiveObjects.getCharacter ((char) 0);
674 }
675 else if (pValue instanceof Character) {
676 return (Character) pValue;
677 }
678 else if (pValue instanceof Boolean) {
679 if (pLogger.isLoggingError ()) {
680 pLogger.logError (Constants.BOOLEAN_TO_CHARACTER, pValue);
681 }
682 return PrimitiveObjects.getCharacter ((char) 0);
683 }
684 else if (pValue instanceof Number) {
685 return PrimitiveObjects.getCharacter
686 ((char) ((Number) pValue).shortValue ());
687 }
688 else if (pValue instanceof String) {
689 String str = (String) pValue;
690 return PrimitiveObjects.getCharacter (str.charAt (0));
691 }
692 else {
693 if (pLogger.isLoggingError ()) {
694 pLogger.logError
695 (Constants.COERCE_TO_CHARACTER,
696 pValue.getClass ().getName ());
697 }
698 return PrimitiveObjects.getCharacter ((char) 0);
699 }
700 }
701
702 //-------------------------------------
703 /**
704 *
705 * Coerces a value to a Boolean
706 **/
707 public static Boolean coerceToBoolean (Object pValue,
708 Logger pLogger)
709 throws ELException
710 {
711 if (pValue == null ||
712 "".equals (pValue)) {
713 return Boolean.FALSE;
714 }
715 else if (pValue instanceof Boolean) {
716 return (Boolean) pValue;
717 }
718 else if (pValue instanceof String) {
719 String str = (String) pValue;
720 try {
721 return Boolean.valueOf (str);
722 }
723 catch (Exception exc) {
724 if (pLogger.isLoggingError ()) {
725 pLogger.logError
726 (Constants.STRING_TO_BOOLEAN,
727 exc,
728 (String) pValue);
729 }
730 return Boolean.FALSE;
731 }
732 }
733 else {
734 if (pLogger.isLoggingError ()) {
735 pLogger.logError
736 (Constants.COERCE_TO_BOOLEAN,
737 pValue.getClass ().getName ());
738 }
739 return Boolean.TRUE;
740 }
741 }
742
743 //-------------------------------------
744 /**
745 *
746 * Coerces a value to the specified Class that is not covered by any
747 * of the above cases
748 **/
749 public static Object coerceToObject (Object pValue,
750 Class pClass,
751 Logger pLogger)
752 throws ELException
753 {
754 if (pValue == null) {
755 return null;
756 }
757 else if (pClass.isAssignableFrom (pValue.getClass ())) {
758 return pValue;
759 }
760 else if (pValue instanceof String) {
761 String str = (String) pValue;
762 PropertyEditor pe = PropertyEditorManager.findEditor (pClass);
763 if (pe == null) {
764 if ("".equals (str)) {
765 return null;
766 }
767 else {
768 if (pLogger.isLoggingError ()) {
769 pLogger.logError
770 (Constants.NO_PROPERTY_EDITOR,
771 str,
772 pClass.getName ());
773 }
774 return null;
775 }
776 }
777 try {
778 pe.setAsText (str);
779 return pe.getValue ();
780 }
781 catch (IllegalArgumentException exc) {
782 if ("".equals (str)) {
783 return null;
784 }
785 else {
786 if (pLogger.isLoggingError ()) {
787 pLogger.logError
788 (Constants.PROPERTY_EDITOR_ERROR,
789 exc,
790 pValue,
791 pClass.getName ());
792 }
793 return null;
794 }
795 }
796 }
797 else {
798 if (pLogger.isLoggingError ()) {
799 pLogger.logError
800 (Constants.COERCE_TO_OBJECT,
801 pValue.getClass ().getName (),
802 pClass.getName ());
803 }
804 return null;
805 }
806 }
807
808 //-------------------------------------
809 // Applying operators
810 //-------------------------------------
811 /**
812 *
813 * Performs all of the necessary type conversions, then calls on the
814 * appropriate operator.
815 **/
816 public static Object applyArithmeticOperator
817 (Object pLeft,
818 Object pRight,
819 ArithmeticOperator pOperator,
820 Logger pLogger)
821 throws ELException
822 {
823 if (pLeft == null &&
824 pRight == null) {
825 if (pLogger.isLoggingWarning ()) {
826 pLogger.logWarning
827 (Constants.ARITH_OP_NULL,
828 pOperator.getOperatorSymbol ());
829 }
830 return PrimitiveObjects.getInteger (0);
831 }
832
833 else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
834 BigDecimal left = (BigDecimal)
835 coerceToPrimitiveNumber(pLeft, BigDecimal.class, pLogger);
836 BigDecimal right = (BigDecimal)
837 coerceToPrimitiveNumber(pRight, BigDecimal.class, pLogger);
838 return pOperator.apply(left, right);
839 }
840
841 else if (isFloatingPointType(pLeft) ||
842 isFloatingPointType(pRight) ||
843 isFloatingPointString(pLeft) ||
844 isFloatingPointString(pRight)) {
845 if (isBigInteger(pLeft) || isBigInteger(pRight)) {
846 BigDecimal left = (BigDecimal)
847 coerceToPrimitiveNumber(pLeft, BigDecimal.class, pLogger);
848 BigDecimal right = (BigDecimal)
849 coerceToPrimitiveNumber(pRight, BigDecimal.class, pLogger);
850 return pOperator.apply(left, right);
851 } else {
852 double left =
853 coerceToPrimitiveNumber(pLeft, Double.class, pLogger).
854 doubleValue();
855 double right =
856 coerceToPrimitiveNumber(pRight, Double.class, pLogger).
857 doubleValue();
858 return
859 PrimitiveObjects.getDouble(pOperator.apply(left, right));
860 }
861 }
862
863 else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
864 BigInteger left = (BigInteger)
865 coerceToPrimitiveNumber(pLeft, BigInteger.class, pLogger);
866 BigInteger right = (BigInteger)
867 coerceToPrimitiveNumber(pRight, BigInteger.class, pLogger);
868 return pOperator.apply(left, right);
869 }
870
871 else {
872 long left =
873 coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
874 longValue ();
875 long right =
876 coerceToPrimitiveNumber (pRight, Long.class, pLogger).
877 longValue ();
878 return
879 PrimitiveObjects.getLong (pOperator.apply (left, right));
880 }
881 }
882
883 //-------------------------------------
884 /**
885 *
886 * Performs all of the necessary type conversions, then calls on the
887 * appropriate operator.
888 **/
889 public static Object applyRelationalOperator
890 (Object pLeft,
891 Object pRight,
892 RelationalOperator pOperator,
893 Logger pLogger)
894 throws ELException
895 {
896 if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
897 BigDecimal left = (BigDecimal)
898 coerceToPrimitiveNumber(pLeft, BigDecimal.class, pLogger);
899 BigDecimal right = (BigDecimal)
900 coerceToPrimitiveNumber(pRight, BigDecimal.class, pLogger);
901 return PrimitiveObjects.getBoolean(pOperator.apply(left, right));
902 }
903
904 else if (isFloatingPointType (pLeft) ||
905 isFloatingPointType (pRight)) {
906 double left =
907 coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
908 doubleValue ();
909 double right =
910 coerceToPrimitiveNumber (pRight, Double.class, pLogger).
911 doubleValue ();
912 return
913 PrimitiveObjects.getBoolean (pOperator.apply (left, right));
914 }
915
916 else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
917 BigInteger left = (BigInteger)
918 coerceToPrimitiveNumber(pLeft, BigInteger.class, pLogger);
919 BigInteger right = (BigInteger)
920 coerceToPrimitiveNumber(pRight, BigInteger.class, pLogger);
921 return PrimitiveObjects.getBoolean(pOperator.apply(left, right));
922 }
923
924 else if (isIntegerType (pLeft) ||
925 isIntegerType (pRight)) {
926 long left =
927 coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
928 longValue ();
929 long right =
930 coerceToPrimitiveNumber (pRight, Long.class, pLogger).
931 longValue ();
932 return
933 PrimitiveObjects.getBoolean (pOperator.apply (left, right));
934 }
935
936 else if (pLeft instanceof String ||
937 pRight instanceof String) {
938 String left = coerceToString (pLeft, pLogger);
939 String right = coerceToString (pRight, pLogger);
940 return
941 PrimitiveObjects.getBoolean (pOperator.apply (left, right));
942 }
943
944 else if (pLeft instanceof Comparable) {
945 try {
946 int result = ((Comparable) pLeft).compareTo (pRight);
947 return
948 PrimitiveObjects.getBoolean
949 (pOperator.apply (result, -result));
950 }
951 catch (Exception exc) {
952 if (pLogger.isLoggingError ()) {
953 pLogger.logError
954 (Constants.COMPARABLE_ERROR,
955 exc,
956 pLeft.getClass ().getName (),
957 (pRight == null) ? "null" : pRight.getClass ().getName (),
958 pOperator.getOperatorSymbol ());
959 }
960 return Boolean.FALSE;
961 }
962 }
963
964 else if (pRight instanceof Comparable) {
965 try {
966 int result = ((Comparable) pRight).compareTo (pLeft);
967 return
968 PrimitiveObjects.getBoolean
969 (pOperator.apply (-result, result));
970 }
971 catch (Exception exc) {
972 if (pLogger.isLoggingError ()) {
973 pLogger.logError
974 (Constants.COMPARABLE_ERROR,
975 exc,
976 pRight.getClass ().getName (),
977 (pLeft == null) ? "null" : pLeft.getClass ().getName (),
978 pOperator.getOperatorSymbol ());
979 }
980 return Boolean.FALSE;
981 }
982 }
983
984 else {
985 if (pLogger.isLoggingError ()) {
986 pLogger.logError
987 (Constants.ARITH_OP_BAD_TYPE,
988 pOperator.getOperatorSymbol (),
989 pLeft.getClass ().getName (),
990 pRight.getClass ().getName ());
991 }
992 return Boolean.FALSE;
993 }
994 }
995
996 //-------------------------------------
997 /**
998 *
999 * Performs all of the necessary type conversions, then calls on the
1000 * appropriate operator.
1001 **/
1002 public static Object applyEqualityOperator
1003 (Object pLeft,
1004 Object pRight,
1005 EqualityOperator pOperator,
1006 Logger pLogger)
1007 throws ELException
1008 {
1009 if (pLeft == pRight) {
1010 return PrimitiveObjects.getBoolean (pOperator.apply (true, pLogger));
1011 }
1012
1013 else if (pLeft == null ||
1014 pRight == null) {
1015 return PrimitiveObjects.getBoolean (pOperator.apply (false, pLogger));
1016 }
1017
1018 else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
1019 BigDecimal left = (BigDecimal)
1020 coerceToPrimitiveNumber(pLeft, BigDecimal.class, pLogger);
1021 BigDecimal right = (BigDecimal)
1022 coerceToPrimitiveNumber(pRight, BigDecimal.class, pLogger);
1023 return PrimitiveObjects.getBoolean(pOperator.apply(left.equals(right), pLogger));
1024 }
1025
1026 else if (isFloatingPointType (pLeft) ||
1027 isFloatingPointType (pRight)) {
1028 double left =
1029 coerceToPrimitiveNumber (pLeft, Double.class, pLogger).
1030 doubleValue ();
1031 double right =
1032 coerceToPrimitiveNumber (pRight, Double.class, pLogger).
1033 doubleValue ();
1034 return
1035 PrimitiveObjects.getBoolean
1036 (pOperator.apply (left == right, pLogger));
1037 }
1038
1039 else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
1040 BigInteger left = (BigInteger)
1041 coerceToPrimitiveNumber(pLeft, BigInteger.class, pLogger);
1042 BigInteger right = (BigInteger)
1043 coerceToPrimitiveNumber(pRight, BigInteger.class, pLogger);
1044 return PrimitiveObjects.getBoolean(pOperator.apply(left.equals(right), pLogger));
1045 }
1046
1047 else if (isIntegerType (pLeft) ||
1048 isIntegerType (pRight)) {
1049 long left =
1050 coerceToPrimitiveNumber (pLeft, Long.class, pLogger).
1051 longValue ();
1052 long right =
1053 coerceToPrimitiveNumber (pRight, Long.class, pLogger).
1054 longValue ();
1055 return
1056 PrimitiveObjects.getBoolean
1057 (pOperator.apply (left == right, pLogger));
1058 }
1059
1060 else if (pLeft instanceof Boolean ||
1061 pRight instanceof Boolean) {
1062 boolean left = coerceToBoolean (pLeft, pLogger).booleanValue ();
1063 boolean right = coerceToBoolean (pRight, pLogger).booleanValue ();
1064 return
1065 PrimitiveObjects.getBoolean
1066 (pOperator.apply (left == right, pLogger));
1067 }
1068
1069 else if (pLeft instanceof String ||
1070 pRight instanceof String) {
1071 String left = coerceToString (pLeft, pLogger);
1072 String right = coerceToString (pRight, pLogger);
1073 return
1074 PrimitiveObjects.getBoolean
1075 (pOperator.apply (left.equals (right), pLogger));
1076 }
1077
1078 else {
1079 try {
1080 return
1081 PrimitiveObjects.getBoolean
1082 (pOperator.apply (pLeft.equals (pRight), pLogger));
1083 }
1084 catch (Exception exc) {
1085 if (pLogger.isLoggingError ()) {
1086 pLogger.logError
1087 (Constants.ERROR_IN_EQUALS,
1088 exc,
1089 pLeft.getClass ().getName (),
1090 pRight.getClass ().getName (),
1091 pOperator.getOperatorSymbol ());
1092 }
1093 return Boolean.FALSE;
1094 }
1095 }
1096 }
1097
1098 //-------------------------------------
1099 /**
1100 *
1101 * Returns true if the given Object is of a floating point type
1102 **/
1103 public static boolean isFloatingPointType (Object pObject)
1104 {
1105 return
1106 pObject != null &&
1107 isFloatingPointType (pObject.getClass ());
1108 }
1109
1110 //-------------------------------------
1111 /**
1112 *
1113 * Returns true if the given class is of a floating point type
1114 **/
1115 public static boolean isFloatingPointType (Class pClass)
1116 {
1117 return
1118 pClass == Float.class ||
1119 pClass == Float.TYPE ||
1120 pClass == Double.class ||
1121 pClass == Double.TYPE;
1122 }
1123
1124 //-------------------------------------
1125 /**
1126 *
1127 * Returns true if the given string might contain a floating point
1128 * number - i.e., it contains ".", "e", or "E"
1129 **/
1130 public static boolean isFloatingPointString (Object pObject)
1131 {
1132 if (pObject instanceof String) {
1133 String str = (String) pObject;
1134 int len = str.length ();
1135 for (int i = 0; i < len; i++) {
1136 char ch = str.charAt (i);
1137 if (ch == '.' ||
1138 ch == 'e' ||
1139 ch == 'E') {
1140 return true;
1141 }
1142 }
1143 return false;
1144 }
1145 else {
1146 return false;
1147 }
1148 }
1149
1150 //-------------------------------------
1151 /**
1152 *
1153 * Returns true if the given Object is of an integer type
1154 **/
1155 public static boolean isIntegerType (Object pObject)
1156 {
1157 return
1158 pObject != null &&
1159 isIntegerType (pObject.getClass ());
1160 }
1161
1162 //-------------------------------------
1163 /**
1164 *
1165 * Returns true if the given class is of an integer type
1166 **/
1167 public static boolean isIntegerType (Class pClass)
1168 {
1169 return
1170 pClass == Byte.class ||
1171 pClass == Byte.TYPE ||
1172 pClass == Short.class ||
1173 pClass == Short.TYPE ||
1174 pClass == Character.class ||
1175 pClass == Character.TYPE ||
1176 pClass == Integer.class ||
1177 pClass == Integer.TYPE ||
1178 pClass == Long.class ||
1179 pClass == Long.TYPE;
1180 }
1181
1182 //-------------------------------------
1183
1184 /**
1185 * Returns true if the given object is BigInteger.
1186 * @param pObject - Object to evaluate
1187 * @return - true if the given object is BigInteger
1188 */
1189 public static boolean isBigInteger(Object pObject) {
1190 return
1191 pObject != null && pObject instanceof BigInteger;
1192 }
1193
1194 /**
1195 * Returns true if the given object is BigDecimal.
1196 * @param pObject - Object to evaluate
1197 * @return - true if the given object is BigDecimal
1198 */
1199 public static boolean isBigDecimal(Object pObject) {
1200 return
1201 pObject != null && pObject instanceof BigDecimal;
1202 }
1203}