0001: /*
0002: * The Apache Software License, Version 1.1
0003: *
0004: * Copyright (c) 1999 The Apache Software Foundation. All rights
0005: * reserved.
0006: *
0007: * Redistribution and use in source and binary forms, with or without
0008: * modification, are permitted provided that the following conditions
0009: * are met:
0010: *
0011: * 1. Redistributions of source code must retain the above copyright
0012: * notice, this list of conditions and the following disclaimer.
0013: *
0014: * 2. Redistributions in binary form must reproduce the above copyright
0015: * notice, this list of conditions and the following disclaimer in
0016: * the documentation and/or other materials provided with the
0017: * distribution.
0018: *
0019: * 3. The end-user documentation included with the redistribution, if
0020: * any, must include the following acknowlegement:
0021: * "This product includes software developed by the
0022: * Apache Software Foundation (http://www.apache.org/)."
0023: * Alternately, this acknowlegement may appear in the software itself,
0024: * if and wherever such third-party acknowlegements normally appear.
0025: *
0026: * 4. The names "The Jakarta Project", "Tomcat", and "Apache Software
0027: * Foundation" must not be used to endorse or promote products derived
0028: * from this software without prior written permission. For written
0029: * permission, please contact apache@apache.org.
0030: *
0031: * 5. Products derived from this software may not be called "Apache"
0032: * nor may "Apache" appear in their names without prior written
0033: * permission of the Apache Group.
0034: *
0035: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
0036: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
0037: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
0038: * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
0039: * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
0040: * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
0041: * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
0042: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
0043: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
0044: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
0045: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
0046: * SUCH DAMAGE.
0047: * ====================================================================
0048: *
0049: * This software consists of voluntary contributions made by many
0050: * individuals on behalf of the Apache Software Foundation. For more
0051: * information on the Apache Software Foundation, please see
0052: * <http://www.apache.org/>.
0053: *
0054: */
0055:
0056: package org.apache.commons.el;
0057:
0058: import java.beans.PropertyEditor;
0059: import java.beans.PropertyEditorManager;
0060: import java.math.BigInteger;
0061: import java.math.BigDecimal;
0062: import javax.servlet.jsp.el.ELException;
0063:
0064: /**
0065: *
0066: * <p>This class contains the logic for coercing data types before
0067: * operators are applied to them.
0068: *
0069: * <p>The following is the list of rules applied for various type
0070: * conversions.
0071: *
0072: * <ul><pre>
0073: * Applying arithmetic operator
0074: * Binary operator - A {+,-,*} B
0075: * if A and B are null
0076: * return 0
0077: * if A or B is BigDecimal, coerce both to BigDecimal and then:
0078: * if operator is +, return <code>A.add(B)</code>
0079: * if operator is -, return <code>A.subtract(B)</code>
0080: * if operator is *, return <code>A.multiply(B)</code>
0081: * if A or B is Float, Double, or String containing ".", "e", or "E"
0082: * if A or B is BigInteger, coerce both A and B to BigDecimal and apply operator
0083: * coerce both A and B to Double and apply operator
0084: * if A or B is BigInteger, coerce both to BigInteger and then:
0085: * if operator is +, return <code>A.add(B)</code>
0086: * if operator is -, return <code>A.subtract(B)</code>
0087: * if operator is *, return <code>A.multiply(B)</code>
0088: * otherwise
0089: * coerce both A and B to Long
0090: * apply operator
0091: * if operator results in exception (such as divide by 0), error
0092: *
0093: * Binary operator - A {/,div} B
0094: * if A and B are null
0095: * return 0
0096: * if A or B is a BigDecimal or BigInteger, coerce both to BigDecimal and
0097: * return <code>A.divide(B, BigDecimal.ROUND_HALF_UP)</code>
0098: * otherwise
0099: * coerce both A and B to Double
0100: * apply operator
0101: * if operator results in exception (such as divide by 0), error
0102: *
0103: * Binary operator - A {%,mod} B
0104: * if A and B are null
0105: * return 0
0106: * if A or B is BigDecimal, Float, Double, or String containing ".", "e" or "E"
0107: * coerce both to Double
0108: * apply operator
0109: * if A or B is BigInteger, coerce both to BigInteger and return
0110: * <code>A.remainder(B)</code>
0111: * otherwise
0112: * coerce both A and B to Long
0113: * apply operator
0114: * if operator results in exception (such as divide by 0), error
0115: *
0116: * Unary minus operator - -A
0117: * if A is null
0118: * return 0
0119: * if A is BigInteger or BigDecimal, return <code>A.negate()</code>
0120: * if A is String
0121: * if A contains ".", "e", or "E"
0122: * coerce to Double, apply operator
0123: * otherwise
0124: * coerce to a Long and apply operator
0125: * if A is Byte,Short,Integer,Long,Float,Double
0126: * retain type, apply operator
0127: * if operator results in exception, error
0128: * otherwise
0129: * error
0130: *
0131: * Applying "empty" operator - empty A
0132: * if A is null
0133: * return true
0134: * if A is zero-length String
0135: * return true
0136: * if A is zero-length array
0137: * return true
0138: * if A is List and ((List) A).isEmpty()
0139: * return true
0140: * if A is Map and ((Map) A).isEmpty()
0141: * return true
0142: * if A is Collection an ((Collection) A).isEmpty()
0143: * return true
0144: * otherwise
0145: * return false
0146: *
0147: * Applying logical operators
0148: * Binary operator - A {and,or} B
0149: * coerce both A and B to Boolean, apply operator
0150: * NOTE - operator stops as soon as expression can be determined, i.e.,
0151: * A and B and C and D - if B is false, then only A and B is evaluated
0152: * Unary not operator - not A
0153: * coerce A to Boolean, apply operator
0154: *
0155: * Applying relational operator
0156: * A {<,>,<=,>=,lt,gt,lte,gte} B
0157: * if A==B
0158: * if operator is >= or <=
0159: * return true
0160: * otherwise
0161: * return false
0162: * if A or B is null
0163: * return false
0164: * if A or B is BigDecimal, coerce both A and B to BigDecimal and use the
0165: * return value of <code>A.compareTo(B)</code>
0166: * if A or B is Float or Double
0167: * coerce both A and B to Double
0168: * apply operator
0169: * if A or B is BigInteger, coerce both A and B to BigInteger and use the
0170: * return value of <code>A.compareTo(B)</code>
0171: * if A or B is Byte,Short,Character,Integer,Long
0172: * coerce both A and B to Long
0173: * apply operator
0174: * if A or B is String
0175: * coerce both A and B to String, compare lexically
0176: * if A is Comparable
0177: * if A.compareTo (B) throws exception
0178: * error
0179: * otherwise
0180: * use result of A.compareTo(B)
0181: * if B is Comparable
0182: * if B.compareTo (A) throws exception
0183: * error
0184: * otherwise
0185: * use result of B.compareTo(A)
0186: * otherwise
0187: * error
0188: *
0189: * Applying equality operator
0190: * A {==,!=} B
0191: * if A==B
0192: * apply operator
0193: * if A or B is null
0194: * return false for ==, true for !=
0195: * if A or B is BigDecimal, coerce both A and B to BigDecimal and then:
0196: * if operator is == or eq, return <code>A.equals(B)</code>
0197: * if operator is != or ne, return <code>!A.equals(B)</code>
0198: * if A or B is Float or Double
0199: * coerce both A and B to Double
0200: * apply operator
0201: * if A or B is BigInteger, coerce both A and B to BigInteger and then:
0202: * if operator is == or eq, return <code>A.equals(B)</code>
0203: * if operator is != or ne, return <code>!A.equals(B)</code>
0204: * if A or B is Byte,Short,Character,Integer,Long
0205: * coerce both A and B to Long
0206: * apply operator
0207: * if A or B is Boolean
0208: * coerce both A and B to Boolean
0209: * apply operator
0210: * if A or B is String
0211: * coerce both A and B to String, compare lexically
0212: * otherwise
0213: * if an error occurs while calling A.equals(B)
0214: * error
0215: * apply operator to result of A.equals(B)
0216: *
0217: * coercions
0218: *
0219: * coerce A to String
0220: * A is String
0221: * return A
0222: * A is null
0223: * return ""
0224: * A.toString throws exception
0225: * error
0226: * otherwise
0227: * return A.toString
0228: *
0229: * coerce A to Number type N
0230: * A is null or ""
0231: * return 0
0232: * A is Character
0233: * convert to short, apply following rules
0234: * A is Boolean
0235: * error
0236: * A is Number type N
0237: * return A
0238: * A is Number, coerce quietly to type N using the following algorithm
0239: * If N is BigInteger
0240: * If A is BigDecimal, return <code>A.toBigInteger()</code>
0241: * Otherwise, return <code>BigInteger.valueOf(A.longValue())</code>
0242: * if N is BigDecimal
0243: * If A is a BigInteger, return <code>new BigDecimal(A)</code>
0244: * Otherwise, return <code>new BigDecimal(A.doubleValue())</code>
0245: * If N is Byte, return <code>new Byte(A.byteValue())</code>
0246: * If N is Short, return <code>new Short(A.shortValue())</code>
0247: * If N is Integer, return <code>new Integer(A.integerValue())</code>
0248: * If N is Long, return <code>new Long(A.longValue())</code>
0249: * If N is Float, return <code>new Float(A.floatValue())</code>
0250: * If N is Double, return <code>new Double(A.doubleValue())</code>
0251: * otherwise ERROR
0252: * A is String
0253: * If N is BigDecimal then:
0254: * If <code>new BigDecimal(A)</code> throws an exception then ERROR
0255: * Otherwise, return <code>new BigDecimal(A)</code>
0256: * If N is BigInteger then:
0257: * If <code>new BigInteger(A)</code> throws an exception, then ERROR
0258: * Otherwise, return <code>new BigInteger(A)</code>
0259: * new <code>N.valueOf(A)</code> throws exception
0260: * error
0261: * return <code>N.valueOf(A)</code>
0262: * otherwise
0263: * error
0264: *
0265: * coerce A to Character should be
0266: * A is null or ""
0267: * return (char) 0
0268: * A is Character
0269: * return A
0270: * A is Boolean
0271: * error
0272: * A is Number with less precision than short
0273: * coerce quietly - return (char) A
0274: * A is Number with greater precision than short
0275: * coerce quietly - return (char) A
0276: * A is String
0277: * return A.charAt (0)
0278: * otherwise
0279: * error
0280: *
0281: * coerce A to Boolean
0282: * A is null or ""
0283: * return false
0284: * A is Boolean
0285: * return A
0286: * A is String
0287: * Boolean.valueOf(A) throws exception
0288: * error
0289: * return Boolean.valueOf(A)
0290: * otherwise
0291: * error
0292: *
0293: * coerce A to any other type T
0294: * A is null
0295: * return null
0296: * A is assignable to T
0297: * coerce quietly
0298: * A is String
0299: * T has no PropertyEditor
0300: * if A is "", return null
0301: * otherwise error
0302: * T's PropertyEditor throws exception
0303: * if A is "", return null
0304: * otherwise error
0305: * otherwise
0306: * apply T's PropertyEditor
0307: * otherwise
0308: * error
0309: * </pre></ul>
0310: *
0311: * @author Nathan Abramson - Art Technology Group
0312: * @version $Change: 181177 $$DateTime: 2001/06/26 08:45:09 $$Author: luehe $
0313: **/
0314:
0315: public class Coercions {
0316: private static final Number ZERO = new Integer(0);
0317:
0318: //-------------------------------------
0319: /**
0320: *
0321: * Coerces the given value to the specified class.
0322: **/
0323: public static Object coerce(Object pValue, Class pClass,
0324: Logger pLogger) throws ELException {
0325: if (pClass == String.class) {
0326: return coerceToString(pValue, pLogger);
0327: } else if (isNumberClass(pClass)) {
0328: return coerceToPrimitiveNumber(pValue, pClass, pLogger);
0329: } else if (pClass == Character.class
0330: || pClass == Character.TYPE) {
0331: return coerceToCharacter(pValue, pLogger);
0332: } else if (pClass == Boolean.class || pClass == Boolean.TYPE) {
0333: return coerceToBoolean(pValue, pLogger);
0334: } else {
0335: return coerceToObject(pValue, pClass, pLogger);
0336: }
0337: }
0338:
0339: //-------------------------------------
0340: /**
0341: *
0342: * Returns true if the given class is Byte, Short, Integer, Long,
0343: * Float, Double, BigInteger, or BigDecimal
0344: **/
0345: static boolean isNumberClass(Class pClass) {
0346: return pClass == Byte.class || pClass == Byte.TYPE
0347: || pClass == Short.class || pClass == Short.TYPE
0348: || pClass == Integer.class || pClass == Integer.TYPE
0349: || pClass == Long.class || pClass == Long.TYPE
0350: || pClass == Float.class || pClass == Float.TYPE
0351: || pClass == Double.class || pClass == Double.TYPE
0352: || pClass == BigInteger.class
0353: || pClass == BigDecimal.class;
0354: }
0355:
0356: //-------------------------------------
0357: /**
0358: *
0359: * Coerces the specified value to a String
0360: **/
0361: public static String coerceToString(Object pValue, Logger pLogger)
0362: throws ELException {
0363: if (pValue == null) {
0364: return "";
0365: } else if (pValue instanceof String) {
0366: return (String) pValue;
0367: } else {
0368: try {
0369: return pValue.toString();
0370: } catch (Exception exc) {
0371: if (pLogger.isLoggingError()) {
0372: pLogger.logError(Constants.TOSTRING_EXCEPTION, exc,
0373: pValue.getClass().getName());
0374: }
0375: return "";
0376: }
0377: }
0378: }
0379:
0380: //-------------------------------------
0381: /**
0382: *
0383: * Coerces a value to the given primitive number class
0384: **/
0385: public static Number coerceToPrimitiveNumber(Object pValue,
0386: Class pClass, Logger pLogger) throws ELException {
0387: if (pValue == null || "".equals(pValue)) {
0388: return coerceToPrimitiveNumber(ZERO, pClass);
0389: } else if (pValue instanceof Character) {
0390: char val = ((Character) pValue).charValue();
0391: return coerceToPrimitiveNumber(new Short((short) val),
0392: pClass);
0393: } else if (pValue instanceof Boolean) {
0394: if (pLogger.isLoggingError()) {
0395: pLogger.logError(Constants.BOOLEAN_TO_NUMBER, pValue,
0396: pClass.getName());
0397: }
0398: return coerceToPrimitiveNumber(ZERO, pClass);
0399: } else if (pValue.getClass() == pClass) {
0400: return (Number) pValue;
0401: } else if (pValue instanceof Number) {
0402: return coerceToPrimitiveNumber((Number) pValue, pClass);
0403: } else if (pValue instanceof String) {
0404: try {
0405: return coerceToPrimitiveNumber((String) pValue, pClass);
0406: } catch (Exception exc) {
0407: if (pLogger.isLoggingError()) {
0408: pLogger.logError(
0409: Constants.STRING_TO_NUMBER_EXCEPTION,
0410: (String) pValue, pClass.getName());
0411: }
0412: return coerceToPrimitiveNumber(ZERO, pClass);
0413: }
0414: } else {
0415: if (pLogger.isLoggingError()) {
0416: pLogger.logError(Constants.COERCE_TO_NUMBER, pValue
0417: .getClass().getName(), pClass.getName());
0418: }
0419: return coerceToPrimitiveNumber(0, pClass);
0420: }
0421: }
0422:
0423: //-------------------------------------
0424: /**
0425: *
0426: * Coerces a value to an Integer, returning null if the coercion
0427: * isn't possible.
0428: **/
0429: public static Integer coerceToInteger(Object pValue, Logger pLogger)
0430: throws ELException {
0431: if (pValue == null) {
0432: return null;
0433: } else if (pValue instanceof Character) {
0434: return PrimitiveObjects
0435: .getInteger((int) (((Character) pValue).charValue()));
0436: } else if (pValue instanceof Boolean) {
0437: if (pLogger.isLoggingWarning()) {
0438: pLogger.logWarning(Constants.BOOLEAN_TO_NUMBER, pValue,
0439: Integer.class.getName());
0440: }
0441: return PrimitiveObjects.getInteger(((Boolean) pValue)
0442: .booleanValue() ? 1 : 0);
0443: } else if (pValue instanceof Integer) {
0444: return (Integer) pValue;
0445: } else if (pValue instanceof Number) {
0446: return PrimitiveObjects.getInteger(((Number) pValue)
0447: .intValue());
0448: } else if (pValue instanceof String) {
0449: try {
0450: return Integer.valueOf((String) pValue);
0451: } catch (Exception exc) {
0452: if (pLogger.isLoggingWarning()) {
0453: pLogger.logWarning(
0454: Constants.STRING_TO_NUMBER_EXCEPTION,
0455: (String) pValue, Integer.class.getName());
0456: }
0457: return null;
0458: }
0459: } else {
0460: if (pLogger.isLoggingWarning()) {
0461: pLogger.logWarning(Constants.COERCE_TO_NUMBER, pValue
0462: .getClass().getName(), Integer.class.getName());
0463: }
0464: return null;
0465: }
0466: }
0467:
0468: //-------------------------------------
0469: /**
0470: *
0471: * Coerces a long to the given primitive number class
0472: **/
0473: static Number coerceToPrimitiveNumber(long pValue, Class pClass)
0474: throws ELException {
0475: if (pClass == Byte.class || pClass == Byte.TYPE) {
0476: return PrimitiveObjects.getByte((byte) pValue);
0477: } else if (pClass == Short.class || pClass == Short.TYPE) {
0478: return PrimitiveObjects.getShort((short) pValue);
0479: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
0480: return PrimitiveObjects.getInteger((int) pValue);
0481: } else if (pClass == Long.class || pClass == Long.TYPE) {
0482: return PrimitiveObjects.getLong(pValue);
0483: } else if (pClass == Float.class || pClass == Float.TYPE) {
0484: return PrimitiveObjects.getFloat((float) pValue);
0485: } else if (pClass == Double.class || pClass == Double.TYPE) {
0486: return PrimitiveObjects.getDouble((double) pValue);
0487: } else {
0488: return PrimitiveObjects.getInteger(0);
0489: }
0490: }
0491:
0492: //-------------------------------------
0493: /**
0494: *
0495: * Coerces a double to the given primitive number class
0496: **/
0497: static Number coerceToPrimitiveNumber(double pValue, Class pClass)
0498: throws ELException {
0499: if (pClass == Byte.class || pClass == Byte.TYPE) {
0500: return PrimitiveObjects.getByte((byte) pValue);
0501: } else if (pClass == Short.class || pClass == Short.TYPE) {
0502: return PrimitiveObjects.getShort((short) pValue);
0503: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
0504: return PrimitiveObjects.getInteger((int) pValue);
0505: } else if (pClass == Long.class || pClass == Long.TYPE) {
0506: return PrimitiveObjects.getLong((long) pValue);
0507: } else if (pClass == Float.class || pClass == Float.TYPE) {
0508: return PrimitiveObjects.getFloat((float) pValue);
0509: } else if (pClass == Double.class || pClass == Double.TYPE) {
0510: return PrimitiveObjects.getDouble(pValue);
0511: } else {
0512: return PrimitiveObjects.getInteger(0);
0513: }
0514: }
0515:
0516: //-------------------------------------
0517: /**
0518: *
0519: * Coerces a Number to the given primitive number class
0520: **/
0521: static Number coerceToPrimitiveNumber(Number pValue, Class pClass)
0522: throws ELException {
0523: if (pClass == Byte.class || pClass == Byte.TYPE) {
0524: return PrimitiveObjects.getByte(pValue.byteValue());
0525: } else if (pClass == Short.class || pClass == Short.TYPE) {
0526: return PrimitiveObjects.getShort(pValue.shortValue());
0527: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
0528: return PrimitiveObjects.getInteger(pValue.intValue());
0529: } else if (pClass == Long.class || pClass == Long.TYPE) {
0530: return PrimitiveObjects.getLong(pValue.longValue());
0531: } else if (pClass == Float.class || pClass == Float.TYPE) {
0532: return PrimitiveObjects.getFloat(pValue.floatValue());
0533: } else if (pClass == Double.class || pClass == Double.TYPE) {
0534: return PrimitiveObjects.getDouble(pValue.doubleValue());
0535: } else if (pClass == BigInteger.class) {
0536: if (pValue instanceof BigDecimal)
0537: return ((BigDecimal) pValue).toBigInteger();
0538: else
0539: return BigInteger.valueOf(pValue.longValue());
0540: } else if (pClass == BigDecimal.class) {
0541: if (pValue instanceof BigInteger)
0542: return new BigDecimal((BigInteger) pValue);
0543: else
0544: return new BigDecimal(pValue.doubleValue());
0545: } else {
0546: return PrimitiveObjects.getInteger(0);
0547: }
0548: }
0549:
0550: //-------------------------------------
0551: /**
0552: *
0553: * Coerces a String to the given primitive number class
0554: **/
0555: static Number coerceToPrimitiveNumber(String pValue, Class pClass)
0556: throws ELException {
0557: if (pClass == Byte.class || pClass == Byte.TYPE) {
0558: return Byte.valueOf(pValue);
0559: } else if (pClass == Short.class || pClass == Short.TYPE) {
0560: return Short.valueOf(pValue);
0561: } else if (pClass == Integer.class || pClass == Integer.TYPE) {
0562: return Integer.valueOf(pValue);
0563: } else if (pClass == Long.class || pClass == Long.TYPE) {
0564: return Long.valueOf(pValue);
0565: } else if (pClass == Float.class || pClass == Float.TYPE) {
0566: return Float.valueOf(pValue);
0567: } else if (pClass == Double.class || pClass == Double.TYPE) {
0568: return Double.valueOf(pValue);
0569: } else if (pClass == BigInteger.class) {
0570: return new BigInteger(pValue);
0571: } else if (pClass == BigDecimal.class) {
0572: return new BigDecimal(pValue);
0573: } else {
0574: return PrimitiveObjects.getInteger(0);
0575: }
0576: }
0577:
0578: //-------------------------------------
0579: /**
0580: *
0581: * Coerces a value to a Character
0582: **/
0583: public static Character coerceToCharacter(Object pValue,
0584: Logger pLogger) throws ELException {
0585: if (pValue == null || "".equals(pValue)) {
0586: return PrimitiveObjects.getCharacter((char) 0);
0587: } else if (pValue instanceof Character) {
0588: return (Character) pValue;
0589: } else if (pValue instanceof Boolean) {
0590: if (pLogger.isLoggingError()) {
0591: pLogger
0592: .logError(Constants.BOOLEAN_TO_CHARACTER,
0593: pValue);
0594: }
0595: return PrimitiveObjects.getCharacter((char) 0);
0596: } else if (pValue instanceof Number) {
0597: return PrimitiveObjects
0598: .getCharacter((char) ((Number) pValue).shortValue());
0599: } else if (pValue instanceof String) {
0600: String str = (String) pValue;
0601: return PrimitiveObjects.getCharacter(str.charAt(0));
0602: } else {
0603: if (pLogger.isLoggingError()) {
0604: pLogger.logError(Constants.COERCE_TO_CHARACTER, pValue
0605: .getClass().getName());
0606: }
0607: return PrimitiveObjects.getCharacter((char) 0);
0608: }
0609: }
0610:
0611: //-------------------------------------
0612: /**
0613: *
0614: * Coerces a value to a Boolean
0615: **/
0616: public static Boolean coerceToBoolean(Object pValue, Logger pLogger)
0617: throws ELException {
0618: if (pValue == null || "".equals(pValue)) {
0619: return Boolean.FALSE;
0620: } else if (pValue instanceof Boolean) {
0621: return (Boolean) pValue;
0622: } else if (pValue instanceof String) {
0623: String str = (String) pValue;
0624: try {
0625: return Boolean.valueOf(str);
0626: } catch (Exception exc) {
0627: if (pLogger.isLoggingError()) {
0628: pLogger.logError(Constants.STRING_TO_BOOLEAN, exc,
0629: (String) pValue);
0630: }
0631: return Boolean.FALSE;
0632: }
0633: } else {
0634: if (pLogger.isLoggingError()) {
0635: pLogger.logError(Constants.COERCE_TO_BOOLEAN, pValue
0636: .getClass().getName());
0637: }
0638: return Boolean.TRUE;
0639: }
0640: }
0641:
0642: //-------------------------------------
0643: /**
0644: *
0645: * Coerces a value to the specified Class that is not covered by any
0646: * of the above cases
0647: **/
0648: public static Object coerceToObject(Object pValue, Class pClass,
0649: Logger pLogger) throws ELException {
0650: if (pValue == null) {
0651: return null;
0652: } else if (pClass.isAssignableFrom(pValue.getClass())) {
0653: return pValue;
0654: } else if (pValue instanceof String) {
0655: String str = (String) pValue;
0656: PropertyEditor pe = PropertyEditorManager
0657: .findEditor(pClass);
0658: if (pe == null) {
0659: if ("".equals(str)) {
0660: return null;
0661: } else {
0662: if (pLogger.isLoggingError()) {
0663: pLogger.logError(Constants.NO_PROPERTY_EDITOR,
0664: str, pClass.getName());
0665: }
0666: return null;
0667: }
0668: }
0669: try {
0670: pe.setAsText(str);
0671: return pe.getValue();
0672: } catch (IllegalArgumentException exc) {
0673: if ("".equals(str)) {
0674: return null;
0675: } else {
0676: if (pLogger.isLoggingError()) {
0677: pLogger.logError(
0678: Constants.PROPERTY_EDITOR_ERROR, exc,
0679: pValue, pClass.getName());
0680: }
0681: return null;
0682: }
0683: }
0684: } else {
0685: if (pLogger.isLoggingError()) {
0686: pLogger.logError(Constants.COERCE_TO_OBJECT, pValue
0687: .getClass().getName(), pClass.getName());
0688: }
0689: return null;
0690: }
0691: }
0692:
0693: //-------------------------------------
0694: // Applying operators
0695: //-------------------------------------
0696: /**
0697: *
0698: * Performs all of the necessary type conversions, then calls on the
0699: * appropriate operator.
0700: **/
0701: public static Object applyArithmeticOperator(Object pLeft,
0702: Object pRight, ArithmeticOperator pOperator, Logger pLogger)
0703: throws ELException {
0704: if (pLeft == null && pRight == null) {
0705: if (pLogger.isLoggingWarning()) {
0706: pLogger.logWarning(Constants.ARITH_OP_NULL, pOperator
0707: .getOperatorSymbol());
0708: }
0709: return PrimitiveObjects.getInteger(0);
0710: }
0711:
0712: else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
0713: BigDecimal left = (BigDecimal) coerceToPrimitiveNumber(
0714: pLeft, BigDecimal.class, pLogger);
0715: BigDecimal right = (BigDecimal) coerceToPrimitiveNumber(
0716: pRight, BigDecimal.class, pLogger);
0717: return pOperator.apply(left, right);
0718: }
0719:
0720: else if (isFloatingPointType(pLeft)
0721: || isFloatingPointType(pRight)
0722: || isFloatingPointString(pLeft)
0723: || isFloatingPointString(pRight)) {
0724: if (isBigInteger(pLeft) || isBigInteger(pRight)) {
0725: BigDecimal left = (BigDecimal) coerceToPrimitiveNumber(
0726: pLeft, BigDecimal.class, pLogger);
0727: BigDecimal right = (BigDecimal) coerceToPrimitiveNumber(
0728: pRight, BigDecimal.class, pLogger);
0729: return pOperator.apply(left, right);
0730: } else {
0731: double left = coerceToPrimitiveNumber(pLeft,
0732: Double.class, pLogger).doubleValue();
0733: double right = coerceToPrimitiveNumber(pRight,
0734: Double.class, pLogger).doubleValue();
0735: return PrimitiveObjects.getDouble(pOperator.apply(left,
0736: right));
0737: }
0738: }
0739:
0740: else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
0741: BigInteger left = (BigInteger) coerceToPrimitiveNumber(
0742: pLeft, BigInteger.class, pLogger);
0743: BigInteger right = (BigInteger) coerceToPrimitiveNumber(
0744: pRight, BigInteger.class, pLogger);
0745: return pOperator.apply(left, right);
0746: }
0747:
0748: else {
0749: long left = coerceToPrimitiveNumber(pLeft, Long.class,
0750: pLogger).longValue();
0751: long right = coerceToPrimitiveNumber(pRight, Long.class,
0752: pLogger).longValue();
0753: return PrimitiveObjects.getLong(pOperator
0754: .apply(left, right));
0755: }
0756: }
0757:
0758: //-------------------------------------
0759: /**
0760: *
0761: * Performs all of the necessary type conversions, then calls on the
0762: * appropriate operator.
0763: **/
0764: public static Object applyRelationalOperator(Object pLeft,
0765: Object pRight, RelationalOperator pOperator, Logger pLogger)
0766: throws ELException {
0767: if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
0768: BigDecimal left = (BigDecimal) coerceToPrimitiveNumber(
0769: pLeft, BigDecimal.class, pLogger);
0770: BigDecimal right = (BigDecimal) coerceToPrimitiveNumber(
0771: pRight, BigDecimal.class, pLogger);
0772: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0773: right));
0774: }
0775:
0776: else if (isFloatingPointType(pLeft)
0777: || isFloatingPointType(pRight)) {
0778: double left = coerceToPrimitiveNumber(pLeft, Double.class,
0779: pLogger).doubleValue();
0780: double right = coerceToPrimitiveNumber(pRight,
0781: Double.class, pLogger).doubleValue();
0782: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0783: right));
0784: }
0785:
0786: else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
0787: BigInteger left = (BigInteger) coerceToPrimitiveNumber(
0788: pLeft, BigInteger.class, pLogger);
0789: BigInteger right = (BigInteger) coerceToPrimitiveNumber(
0790: pRight, BigInteger.class, pLogger);
0791: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0792: right));
0793: }
0794:
0795: else if (isIntegerType(pLeft) || isIntegerType(pRight)) {
0796: long left = coerceToPrimitiveNumber(pLeft, Long.class,
0797: pLogger).longValue();
0798: long right = coerceToPrimitiveNumber(pRight, Long.class,
0799: pLogger).longValue();
0800: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0801: right));
0802: }
0803:
0804: else if (pLeft instanceof String || pRight instanceof String) {
0805: String left = coerceToString(pLeft, pLogger);
0806: String right = coerceToString(pRight, pLogger);
0807: return PrimitiveObjects.getBoolean(pOperator.apply(left,
0808: right));
0809: }
0810:
0811: else if (pLeft instanceof Comparable) {
0812: try {
0813: int result = ((Comparable) pLeft).compareTo(pRight);
0814: return PrimitiveObjects.getBoolean(pOperator.apply(
0815: result, -result));
0816: } catch (Exception exc) {
0817: if (pLogger.isLoggingError()) {
0818: pLogger.logError(Constants.COMPARABLE_ERROR, exc,
0819: pLeft.getClass().getName(),
0820: (pRight == null) ? "null" : pRight
0821: .getClass().getName(), pOperator
0822: .getOperatorSymbol());
0823: }
0824: return Boolean.FALSE;
0825: }
0826: }
0827:
0828: else if (pRight instanceof Comparable) {
0829: try {
0830: int result = ((Comparable) pRight).compareTo(pLeft);
0831: return PrimitiveObjects.getBoolean(pOperator.apply(
0832: -result, result));
0833: } catch (Exception exc) {
0834: if (pLogger.isLoggingError()) {
0835: pLogger.logError(Constants.COMPARABLE_ERROR, exc,
0836: pRight.getClass().getName(),
0837: (pLeft == null) ? "null" : pLeft.getClass()
0838: .getName(), pOperator
0839: .getOperatorSymbol());
0840: }
0841: return Boolean.FALSE;
0842: }
0843: }
0844:
0845: else {
0846: if (pLogger.isLoggingError()) {
0847: pLogger.logError(Constants.ARITH_OP_BAD_TYPE, pOperator
0848: .getOperatorSymbol(), pLeft.getClass()
0849: .getName(), pRight.getClass().getName());
0850: }
0851: return Boolean.FALSE;
0852: }
0853: }
0854:
0855: //-------------------------------------
0856: /**
0857: *
0858: * Performs all of the necessary type conversions, then calls on the
0859: * appropriate operator.
0860: **/
0861: public static Object applyEqualityOperator(Object pLeft,
0862: Object pRight, EqualityOperator pOperator, Logger pLogger)
0863: throws ELException {
0864: if (pLeft == pRight) {
0865: return PrimitiveObjects.getBoolean(pOperator.apply(true,
0866: pLogger));
0867: }
0868:
0869: else if (pLeft == null || pRight == null) {
0870: return PrimitiveObjects.getBoolean(pOperator.apply(false,
0871: pLogger));
0872: }
0873:
0874: else if (isBigDecimal(pLeft) || isBigDecimal(pRight)) {
0875: BigDecimal left = (BigDecimal) coerceToPrimitiveNumber(
0876: pLeft, BigDecimal.class, pLogger);
0877: BigDecimal right = (BigDecimal) coerceToPrimitiveNumber(
0878: pRight, BigDecimal.class, pLogger);
0879: return PrimitiveObjects.getBoolean(pOperator.apply(left
0880: .equals(right), pLogger));
0881: }
0882:
0883: else if (isFloatingPointType(pLeft)
0884: || isFloatingPointType(pRight)) {
0885: double left = coerceToPrimitiveNumber(pLeft, Double.class,
0886: pLogger).doubleValue();
0887: double right = coerceToPrimitiveNumber(pRight,
0888: Double.class, pLogger).doubleValue();
0889: return PrimitiveObjects.getBoolean(pOperator.apply(
0890: left == right, pLogger));
0891: }
0892:
0893: else if (isBigInteger(pLeft) || isBigInteger(pRight)) {
0894: BigInteger left = (BigInteger) coerceToPrimitiveNumber(
0895: pLeft, BigInteger.class, pLogger);
0896: BigInteger right = (BigInteger) coerceToPrimitiveNumber(
0897: pRight, BigInteger.class, pLogger);
0898: return PrimitiveObjects.getBoolean(pOperator.apply(left
0899: .equals(right), pLogger));
0900: }
0901:
0902: else if (isIntegerType(pLeft) || isIntegerType(pRight)) {
0903: long left = coerceToPrimitiveNumber(pLeft, Long.class,
0904: pLogger).longValue();
0905: long right = coerceToPrimitiveNumber(pRight, Long.class,
0906: pLogger).longValue();
0907: return PrimitiveObjects.getBoolean(pOperator.apply(
0908: left == right, pLogger));
0909: }
0910:
0911: else if (pLeft instanceof Boolean || pRight instanceof Boolean) {
0912: boolean left = coerceToBoolean(pLeft, pLogger)
0913: .booleanValue();
0914: boolean right = coerceToBoolean(pRight, pLogger)
0915: .booleanValue();
0916: return PrimitiveObjects.getBoolean(pOperator.apply(
0917: left == right, pLogger));
0918: }
0919:
0920: else if (pLeft instanceof String || pRight instanceof String) {
0921: String left = coerceToString(pLeft, pLogger);
0922: String right = coerceToString(pRight, pLogger);
0923: return PrimitiveObjects.getBoolean(pOperator.apply(left
0924: .equals(right), pLogger));
0925: }
0926:
0927: else {
0928: try {
0929: return PrimitiveObjects.getBoolean(pOperator.apply(
0930: pLeft.equals(pRight), pLogger));
0931: } catch (Exception exc) {
0932: if (pLogger.isLoggingError()) {
0933: pLogger.logError(Constants.ERROR_IN_EQUALS, exc,
0934: pLeft.getClass().getName(), pRight
0935: .getClass().getName(), pOperator
0936: .getOperatorSymbol());
0937: }
0938: return Boolean.FALSE;
0939: }
0940: }
0941: }
0942:
0943: //-------------------------------------
0944: /**
0945: *
0946: * Returns true if the given Object is of a floating point type
0947: **/
0948: public static boolean isFloatingPointType(Object pObject) {
0949: return pObject != null
0950: && isFloatingPointType(pObject.getClass());
0951: }
0952:
0953: //-------------------------------------
0954: /**
0955: *
0956: * Returns true if the given class is of a floating point type
0957: **/
0958: public static boolean isFloatingPointType(Class pClass) {
0959: return pClass == Float.class || pClass == Float.TYPE
0960: || pClass == Double.class || pClass == Double.TYPE;
0961: }
0962:
0963: //-------------------------------------
0964: /**
0965: *
0966: * Returns true if the given string might contain a floating point
0967: * number - i.e., it contains ".", "e", or "E"
0968: **/
0969: public static boolean isFloatingPointString(Object pObject) {
0970: if (pObject instanceof String) {
0971: String str = (String) pObject;
0972: int len = str.length();
0973: for (int i = 0; i < len; i++) {
0974: char ch = str.charAt(i);
0975: if (ch == '.' || ch == 'e' || ch == 'E') {
0976: return true;
0977: }
0978: }
0979: return false;
0980: } else {
0981: return false;
0982: }
0983: }
0984:
0985: //-------------------------------------
0986: /**
0987: *
0988: * Returns true if the given Object is of an integer type
0989: **/
0990: public static boolean isIntegerType(Object pObject) {
0991: return pObject != null && isIntegerType(pObject.getClass());
0992: }
0993:
0994: //-------------------------------------
0995: /**
0996: *
0997: * Returns true if the given class is of an integer type
0998: **/
0999: public static boolean isIntegerType(Class pClass) {
1000: return pClass == Byte.class || pClass == Byte.TYPE
1001: || pClass == Short.class || pClass == Short.TYPE
1002: || pClass == Character.class
1003: || pClass == Character.TYPE || pClass == Integer.class
1004: || pClass == Integer.TYPE || pClass == Long.class
1005: || pClass == Long.TYPE;
1006: }
1007:
1008: //-------------------------------------
1009:
1010: /**
1011: * Returns true if the given object is BigInteger.
1012: * @param pObject - Object to evaluate
1013: * @return - true if the given object is BigInteger
1014: */
1015: public static boolean isBigInteger(Object pObject) {
1016: return pObject != null && pObject instanceof BigInteger;
1017: }
1018:
1019: /**
1020: * Returns true if the given object is BigDecimal.
1021: * @param pObject - Object to evaluate
1022: * @return - true if the given object is BigDecimal
1023: */
1024: public static boolean isBigDecimal(Object pObject) {
1025: return pObject != null && pObject instanceof BigDecimal;
1026: }
1027: }
|