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