001: //--------------------------------------------------------------------------
002: // Copyright (c) 1998-2004, Drew Davidson and Luke Blanshard
003: // All rights reserved.
004: //
005: // Redistribution and use in source and binary forms, with or without
006: // modification, are permitted provided that the following conditions are
007: // met:
008: //
009: // Redistributions of source code must retain the above copyright notice,
010: // this list of conditions and the following disclaimer.
011: // Redistributions in binary form must reproduce the above copyright
012: // notice, this list of conditions and the following disclaimer in the
013: // documentation and/or other materials provided with the distribution.
014: // Neither the name of the Drew Davidson nor the names of its contributors
015: // may be used to endorse or promote products derived from this software
016: // without specific prior written permission.
017: //
018: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
019: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
020: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
021: // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
022: // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
023: // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
024: // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
025: // OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
026: // AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
027: // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
028: // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
029: // DAMAGE.
030: //--------------------------------------------------------------------------
031: package ognl;
032:
033: import java.lang.reflect.Array;
034: import java.math.BigDecimal;
035: import java.math.BigInteger;
036: import java.util.Enumeration;
037:
038: /**
039: * This is an abstract class with static methods that define the operations of OGNL.
040: * @author Luke Blanshard (blanshlu@netscape.net)
041: * @author Drew Davidson (drew@ognl.org)
042: */
043: public abstract class OgnlOps implements NumericTypes {
044: /**
045: * Compares two objects for equality, even if it has to convert
046: * one of them to the other type. If both objects are numeric
047: * they are converted to the widest type and compared. If
048: * one is non-numeric and one is numeric the non-numeric is
049: * converted to double and compared to the double numeric
050: * value. If both are non-numeric and Comparable and the
051: * types are compatible (i.e. v1 is of the same or superclass
052: * of v2's type) they are compared with Comparable.compareTo().
053: * If both values are non-numeric and not Comparable or of
054: * incompatible classes this will throw and IllegalArgumentException.
055: *
056: * @param v1 First value to compare
057: * @param v2 second value to compare
058: *
059: * @return integer describing the comparison between the two objects.
060: * A negative number indicates that v1 < v2. Positive indicates
061: * that v1 > v2. Zero indicates v1 == v2.
062: *
063: * @throws IllegalArgumentException if the objects are both non-numeric
064: * yet of incompatible types or do not implement Comparable.
065: */
066: public static int compareWithConversion(Object v1, Object v2) {
067: return compareWithConversion(v1, v2, false);
068: }
069:
070: /**
071: * Compares two objects for equality, even if it has to convert
072: * one of them to the other type. If both objects are numeric
073: * they are converted to the widest type and compared. If
074: * one is non-numeric and one is numeric the non-numeric is
075: * converted to double and compared to the double numeric
076: * value. If both are non-numeric and Comparable and the
077: * types are compatible (i.e. v1 is of the same or superclass
078: * of v2's type) they are compared with Comparable.compareTo().
079: * If both values are non-numeric and not Comparable or of
080: * incompatible classes this will throw and IllegalArgumentException.
081: *
082: * @param v1 First value to compare
083: * @param v2 second value to compare
084: *
085: * @return integer describing the comparison between the two objects.
086: * A negative number indicates that v1 < v2. Positive indicates
087: * that v1 > v2. Zero indicates v1 == v2.
088: *
089: * @throws IllegalArgumentException if the objects are both non-numeric
090: * yet of incompatible types or do not implement Comparable.
091: */
092: public static int compareWithConversion(Object v1, Object v2,
093: boolean equals) {
094: int result;
095:
096: if (v1 == v2) {
097: result = 0;
098: } else {
099: int t1 = getNumericType(v1), t2 = getNumericType(v2), type = getNumericType(
100: t1, t2, true);
101:
102: switch (type) {
103: case BIGINT:
104: result = bigIntValue(v1).compareTo(bigIntValue(v2));
105: break;
106:
107: case BIGDEC:
108: result = bigDecValue(v1).compareTo(bigDecValue(v2));
109: break;
110:
111: case NONNUMERIC:
112: if ((t1 == NONNUMERIC) && (t2 == NONNUMERIC)) {
113: if ((v1 == null) || (v2 == null)) {
114: result = (v1 == v2) ? 0 : 1;
115: } else {
116: if (v1.getClass().isAssignableFrom(
117: v2.getClass())
118: || v2.getClass().isAssignableFrom(
119: v1.getClass())) {
120: if (v1 instanceof Comparable) {
121: result = ((Comparable) v1)
122: .compareTo(v2);
123: break;
124: } else {
125: if (equals) {
126: result = v1.equals(v2) ? 0 : 1;
127: break;
128: }
129: }
130: }
131: if (equals) {
132: // Equals comparison between non-numerics that are not of a common
133: // superclass return not equal
134: result = 1;
135: break;
136: } else {
137: throw new IllegalArgumentException(
138: "invalid comparison: "
139: + v1.getClass().getName()
140: + " and "
141: + v2.getClass().getName());
142: }
143: }
144: }
145: // else fall through
146: case FLOAT:
147: case DOUBLE:
148: double dv1 = doubleValue(v1),
149: dv2 = doubleValue(v2);
150:
151: return (dv1 == dv2) ? 0 : ((dv1 < dv2) ? -1 : 1);
152:
153: default:
154: long lv1 = longValue(v1),
155: lv2 = longValue(v2);
156:
157: return (lv1 == lv2) ? 0 : ((lv1 < lv2) ? -1 : 1);
158: }
159: }
160: return result;
161: }
162:
163: /**
164: * Returns true if object1 is equal to object2 in either the
165: * sense that they are the same object or, if both are non-null
166: * if they are equal in the <CODE>equals()</CODE> sense.
167: *
168: * @param v1 First object to compare
169: * @param v2 Second object to compare
170: *
171: * @return true if v1 == v2
172: */
173: public static boolean isEqual(Object object1, Object object2) {
174: boolean result = false;
175:
176: if (object1 == object2) {
177: result = true;
178: } else {
179: if ((object1 != null) && (object2 != null)) {
180: if (object1.getClass().isArray()
181: && object2.getClass().isArray()
182: && (object2.getClass() == object1.getClass())) {
183: result = (Array.getLength(object1) == Array
184: .getLength(object2));
185: if (result) {
186: for (int i = 0, icount = Array
187: .getLength(object1); result
188: && (i < icount); i++) {
189: result = isEqual(Array.get(object1, i),
190: Array.get(object2, i));
191: }
192: }
193: } else {
194: if ((object1 != null) && (object2 != null)) {
195: // Check for converted equivalence first, then equals() equivalence
196: result = (compareWithConversion(object1,
197: object2, true) == 0)
198: || object1.equals(object2);
199: }
200: }
201: }
202: }
203: return result;
204: }
205:
206: /**
207: * Evaluates the given object as a boolean: if it is a Boolean object, it's easy; if
208: * it's a Number or a Character, returns true for non-zero objects; and otherwise
209: * returns true for non-null objects.
210: *
211: * @param value an object to interpret as a boolean
212: * @return the boolean value implied by the given object
213: */
214: public static boolean booleanValue(Object value) {
215: if (value == null)
216: return false;
217: Class c = value.getClass();
218: if (c == Boolean.class)
219: return ((Boolean) value).booleanValue();
220: // if ( c == String.class )
221: // return ((String)value).length() > 0;
222: if (c == Character.class)
223: return ((Character) value).charValue() != 0;
224: if (value instanceof Number)
225: return ((Number) value).doubleValue() != 0;
226: return true; // non-null
227: }
228:
229: /**
230: * Evaluates the given object as a long integer.
231: *
232: * @param value an object to interpret as a long integer
233: * @return the long integer value implied by the given object
234: * @throws NumberFormatException if the given object can't be understood as a long integer
235: */
236: public static long longValue(Object value)
237: throws NumberFormatException {
238: if (value == null)
239: return 0L;
240: Class c = value.getClass();
241: if (c.getSuperclass() == Number.class)
242: return ((Number) value).longValue();
243: if (c == Boolean.class)
244: return ((Boolean) value).booleanValue() ? 1 : 0;
245: if (c == Character.class)
246: return ((Character) value).charValue();
247: return Long.parseLong(stringValue(value, true));
248: }
249:
250: /**
251: * Evaluates the given object as a double-precision floating-point number.
252: *
253: * @param value an object to interpret as a double
254: * @return the double value implied by the given object
255: * @throws NumberFormatException if the given object can't be understood as a double
256: */
257: public static double doubleValue(Object value)
258: throws NumberFormatException {
259: if (value == null)
260: return 0.0;
261: Class c = value.getClass();
262: if (c.getSuperclass() == Number.class)
263: return ((Number) value).doubleValue();
264: if (c == Boolean.class)
265: return ((Boolean) value).booleanValue() ? 1 : 0;
266: if (c == Character.class)
267: return ((Character) value).charValue();
268: String s = stringValue(value, true);
269:
270: return (s.length() == 0) ? 0.0 : Double.parseDouble(s);
271: /*
272: For 1.1 parseDouble() is not available
273: */
274: //return Double.valueOf( value.toString() ).doubleValue();
275: }
276:
277: /**
278: * Evaluates the given object as a BigInteger.
279: *
280: * @param value an object to interpret as a BigInteger
281: * @return the BigInteger value implied by the given object
282: * @throws NumberFormatException if the given object can't be understood as a BigInteger
283: */
284: public static BigInteger bigIntValue(Object value)
285: throws NumberFormatException {
286: if (value == null)
287: return BigInteger.valueOf(0L);
288: Class c = value.getClass();
289: if (c == BigInteger.class)
290: return (BigInteger) value;
291: if (c == BigDecimal.class)
292: return ((BigDecimal) value).toBigInteger();
293: if (c.getSuperclass() == Number.class)
294: return BigInteger.valueOf(((Number) value).longValue());
295: if (c == Boolean.class)
296: return BigInteger
297: .valueOf(((Boolean) value).booleanValue() ? 1 : 0);
298: if (c == Character.class)
299: return BigInteger.valueOf(((Character) value).charValue());
300: return new BigInteger(stringValue(value, true));
301: }
302:
303: /**
304: * Evaluates the given object as a BigDecimal.
305: *
306: * @param value an object to interpret as a BigDecimal
307: * @return the BigDecimal value implied by the given object
308: * @throws NumberFormatException if the given object can't be understood as a BigDecimal
309: */
310: public static BigDecimal bigDecValue(Object value)
311: throws NumberFormatException {
312: if (value == null)
313: return BigDecimal.valueOf(0L);
314: Class c = value.getClass();
315: if (c == BigDecimal.class)
316: return (BigDecimal) value;
317: if (c == BigInteger.class)
318: return new BigDecimal((BigInteger) value);
319: if (c.getSuperclass() == Number.class)
320: return new BigDecimal(((Number) value).doubleValue());
321: if (c == Boolean.class)
322: return BigDecimal
323: .valueOf(((Boolean) value).booleanValue() ? 1 : 0);
324: if (c == Character.class)
325: return BigDecimal.valueOf(((Character) value).charValue());
326: return new BigDecimal(stringValue(value, true));
327: }
328:
329: /**
330: * Evaluates the given object as a String and trims it if the trim flag is true.
331: *
332: * @param value an object to interpret as a String
333: * @return the String value implied by the given object as returned by the toString() method,
334: or "null" if the object is null.
335: */
336: public static String stringValue(Object value, boolean trim) {
337: String result;
338:
339: if (value == null) {
340: result = OgnlRuntime.NULL_STRING;
341: } else {
342: result = value.toString();
343: if (trim) {
344: result = result.trim();
345: }
346: }
347: return result;
348: }
349:
350: /**
351: * Evaluates the given object as a String.
352: *
353: * @param value an object to interpret as a String
354: * @return the String value implied by the given object as returned by the toString() method,
355: or "null" if the object is null.
356: */
357: public static String stringValue(Object value) {
358: return stringValue(value, false);
359: }
360:
361: /**
362: * Returns a constant from the NumericTypes interface that represents the numeric
363: * type of the given object.
364: *
365: * @param value an object that needs to be interpreted as a number
366: * @return the appropriate constant from the NumericTypes interface
367: */
368: public static int getNumericType(Object value) {
369: int result = NONNUMERIC;
370:
371: if (value != null) {
372: Class c = value.getClass();
373: if (c == Integer.class)
374: return INT;
375: if (c == Double.class)
376: return DOUBLE;
377: if (c == Boolean.class)
378: return BOOL;
379: if (c == Byte.class)
380: return BYTE;
381: if (c == Character.class)
382: return CHAR;
383: if (c == Short.class)
384: return SHORT;
385: if (c == Long.class)
386: return LONG;
387: if (c == Float.class)
388: return FLOAT;
389: if (c == BigInteger.class)
390: return BIGINT;
391: if (c == BigDecimal.class)
392: return BIGDEC;
393: }
394: return NONNUMERIC;
395: }
396:
397: /**
398: * Returns the value converted numerically to the given class type
399: *
400: * This method also detects when arrays are being converted and
401: * converts the components of one array to the type of the other.
402: *
403: * @param value an object to be converted to the given type
404: * @param toType class type to be converted to
405: * @return converted value of the type given, or value if the value
406: * cannot be converted to the given type.
407: */
408: public static Object convertValue(Object value, Class toType) {
409: Object result = null;
410:
411: if (value != null) {
412: /* If array -> array then convert components of array individually */
413: if (value.getClass().isArray() && toType.isArray()) {
414: Class componentType = toType.getComponentType();
415:
416: result = Array.newInstance(componentType, Array
417: .getLength(value));
418: for (int i = 0, icount = Array.getLength(value); i < icount; i++) {
419: Array.set(result, i, convertValue(Array.get(value,
420: i), componentType));
421: }
422: } else {
423: if ((toType == Integer.class)
424: || (toType == Integer.TYPE))
425: result = new Integer((int) longValue(value));
426: if ((toType == Double.class) || (toType == Double.TYPE))
427: result = new Double(doubleValue(value));
428: if ((toType == Boolean.class)
429: || (toType == Boolean.TYPE))
430: result = booleanValue(value) ? Boolean.TRUE
431: : Boolean.FALSE;
432: if ((toType == Byte.class) || (toType == Byte.TYPE))
433: result = new Byte((byte) longValue(value));
434: if ((toType == Character.class)
435: || (toType == Character.TYPE))
436: result = new Character((char) longValue(value));
437: if ((toType == Short.class) || (toType == Short.TYPE))
438: result = new Short((short) longValue(value));
439: if ((toType == Long.class) || (toType == Long.TYPE))
440: result = new Long(longValue(value));
441: if ((toType == Float.class) || (toType == Float.TYPE))
442: result = new Float(doubleValue(value));
443: if (toType == BigInteger.class)
444: result = bigIntValue(value);
445: if (toType == BigDecimal.class)
446: result = bigDecValue(value);
447: if (toType == String.class)
448: result = stringValue(value);
449: }
450: } else {
451: if (toType.isPrimitive()) {
452: result = OgnlRuntime.getPrimitiveDefaultValue(toType);
453: }
454: }
455: return result;
456: }
457:
458: /**
459: * Returns the constant from the NumericTypes interface that best expresses the type
460: * of a numeric operation on the two given objects.
461: *
462: * @param v1 one argument to a numeric operator
463: * @param v2 the other argument
464: * @return the appropriate constant from the NumericTypes interface
465: */
466: public static int getNumericType(Object v1, Object v2) {
467: return getNumericType(v1, v2, false);
468: }
469:
470: /**
471: * Returns the constant from the NumericTypes interface that best expresses the type
472: * of an operation, which can be either numeric or not, on the two given types.
473: *
474: * @param t1 type of one argument to an operator
475: * @param t2 type of the other argument
476: * @param canBeNonNumeric whether the operator can be interpreted as non-numeric
477: * @return the appropriate constant from the NumericTypes interface
478: */
479: public static int getNumericType(int t1, int t2,
480: boolean canBeNonNumeric) {
481: if (t1 == t2)
482: return t1;
483:
484: if (canBeNonNumeric
485: && (t1 == NONNUMERIC || t2 == NONNUMERIC || t1 == CHAR || t2 == CHAR))
486: return NONNUMERIC;
487:
488: if (t1 == NONNUMERIC)
489: t1 = DOUBLE; // Try to interpret strings as doubles...
490: if (t2 == NONNUMERIC)
491: t2 = DOUBLE; // Try to interpret strings as doubles...
492:
493: if (t1 >= MIN_REAL_TYPE) {
494: if (t2 >= MIN_REAL_TYPE)
495: return Math.max(t1, t2);
496: if (t2 < INT)
497: return t1;
498: if (t2 == BIGINT)
499: return BIGDEC;
500: return Math.max(DOUBLE, t1);
501: } else if (t2 >= MIN_REAL_TYPE) {
502: if (t1 < INT)
503: return t2;
504: if (t1 == BIGINT)
505: return BIGDEC;
506: return Math.max(DOUBLE, t2);
507: } else
508: return Math.max(t1, t2);
509: }
510:
511: /**
512: * Returns the constant from the NumericTypes interface that best expresses the type
513: * of an operation, which can be either numeric or not, on the two given objects.
514: *
515: * @param v1 one argument to an operator
516: * @param v2 the other argument
517: * @param canBeNonNumeric whether the operator can be interpreted as non-numeric
518: * @return the appropriate constant from the NumericTypes interface
519: */
520: public static int getNumericType(Object v1, Object v2,
521: boolean canBeNonNumeric) {
522: return getNumericType(getNumericType(v1), getNumericType(v2),
523: canBeNonNumeric);
524: }
525:
526: /**
527: * Returns a new Number object of an appropriate type to hold the given integer
528: * value. The type of the returned object is consistent with the given type
529: * argument, which is a constant from the NumericTypes interface.
530: *
531: * @param type the nominal numeric type of the result, a constant from the NumericTypes interface
532: * @param value the integer value to convert to a Number object
533: * @return a Number object with the given value, of type implied by the type argument
534: */
535: public static Number newInteger(int type, long value) {
536: switch (type) {
537: case BOOL:
538: case CHAR:
539: case INT:
540: return new Integer((int) value);
541:
542: case FLOAT:
543: if ((long) (float) value == value) {
544: return new Float((float) value);
545: }
546: // else fall through:
547: case DOUBLE:
548: if ((long) (double) value == value) {
549: return new Double((double) value);
550: }
551: // else fall through:
552: case LONG:
553: return new Long(value);
554:
555: case BYTE:
556: return new Byte((byte) value);
557:
558: case SHORT:
559: return new Short((short) value);
560:
561: default:
562: return BigInteger.valueOf(value);
563: }
564: }
565:
566: /**
567: * Returns a new Number object of an appropriate type to hold the given real value.
568: * The type of the returned object is always either Float or Double, and is only
569: * Float if the given type tag (a constant from the NumericTypes interface) is
570: * FLOAT.
571: *
572: * @param type the nominal numeric type of the result, a constant from the NumericTypes interface
573: * @param value the real value to convert to a Number object
574: * @return a Number object with the given value, of type implied by the type argument
575: */
576: public static Number newReal(int type, double value) {
577: if (type == FLOAT)
578: return new Float((float) value);
579: return new Double(value);
580: }
581:
582: public static Object binaryOr(Object v1, Object v2) {
583: int type = getNumericType(v1, v2);
584: if (type == BIGINT || type == BIGDEC)
585: return bigIntValue(v1).or(bigIntValue(v2));
586: return newInteger(type, longValue(v1) | longValue(v2));
587: }
588:
589: public static Object binaryXor(Object v1, Object v2) {
590: int type = getNumericType(v1, v2);
591: if (type == BIGINT || type == BIGDEC)
592: return bigIntValue(v1).xor(bigIntValue(v2));
593: return newInteger(type, longValue(v1) ^ longValue(v2));
594: }
595:
596: public static Object binaryAnd(Object v1, Object v2) {
597: int type = getNumericType(v1, v2);
598: if (type == BIGINT || type == BIGDEC)
599: return bigIntValue(v1).and(bigIntValue(v2));
600: return newInteger(type, longValue(v1) & longValue(v2));
601: }
602:
603: public static boolean equal(Object v1, Object v2) {
604: if (v1 == null)
605: return v2 == null;
606: if (v1 == v2 || isEqual(v1, v2))
607: return true;
608: if (v1 instanceof Number && v2 instanceof Number)
609: return ((Number) v1).doubleValue() == ((Number) v2)
610: .doubleValue();
611: return false;
612: }
613:
614: public static boolean less(Object v1, Object v2) {
615: return compareWithConversion(v1, v2) < 0;
616: }
617:
618: public static boolean greater(Object v1, Object v2) {
619: return compareWithConversion(v1, v2) > 0;
620: }
621:
622: public static boolean in(Object v1, Object v2) throws OgnlException {
623: if (v2 == null) // A null collection is always treated as empty
624: return false;
625:
626: ElementsAccessor elementsAccessor = OgnlRuntime
627: .getElementsAccessor(OgnlRuntime.getTargetClass(v2));
628: for (Enumeration e = elementsAccessor.getElements(v2); e
629: .hasMoreElements();) {
630: Object o = e.nextElement();
631:
632: if (equal(v1, o))
633: return true;
634: }
635: return false;
636: }
637:
638: public static Object shiftLeft(Object v1, Object v2) {
639: int type = getNumericType(v1);
640: if (type == BIGINT || type == BIGDEC)
641: return bigIntValue(v1).shiftLeft((int) longValue(v2));
642: return newInteger(type, longValue(v1) << (int) longValue(v2));
643: }
644:
645: public static Object shiftRight(Object v1, Object v2) {
646: int type = getNumericType(v1);
647: if (type == BIGINT || type == BIGDEC)
648: return bigIntValue(v1).shiftRight((int) longValue(v2));
649: return newInteger(type, longValue(v1) >> (int) longValue(v2));
650: }
651:
652: public static Object unsignedShiftRight(Object v1, Object v2) {
653: int type = getNumericType(v1);
654: if (type == BIGINT || type == BIGDEC)
655: return bigIntValue(v1).shiftRight((int) longValue(v2));
656: if (type <= INT)
657: return newInteger(INT,
658: ((int) longValue(v1)) >>> (int) longValue(v2));
659: return newInteger(type, longValue(v1) >>> (int) longValue(v2));
660: }
661:
662: public static Object add(Object v1, Object v2) {
663: int type = getNumericType(v1, v2, true);
664: switch (type) {
665: case BIGINT:
666: return bigIntValue(v1).add(bigIntValue(v2));
667: case BIGDEC:
668: return bigDecValue(v1).add(bigDecValue(v2));
669: case FLOAT:
670: case DOUBLE:
671: return newReal(type, doubleValue(v1) + doubleValue(v2));
672: case NONNUMERIC:
673: int t1 = getNumericType(v1),
674: t2 = getNumericType(v2);
675:
676: if (((t1 != NONNUMERIC) && (v2 == null))
677: || ((t2 != NONNUMERIC) && (v1 == null))) {
678: throw new NullPointerException();
679: }
680: return stringValue(v1) + stringValue(v2);
681: default:
682: return newInteger(type, longValue(v1) + longValue(v2));
683: }
684: }
685:
686: public static Object subtract(Object v1, Object v2) {
687: int type = getNumericType(v1, v2);
688: switch (type) {
689: case BIGINT:
690: return bigIntValue(v1).subtract(bigIntValue(v2));
691: case BIGDEC:
692: return bigDecValue(v1).subtract(bigDecValue(v2));
693: case FLOAT:
694: case DOUBLE:
695: return newReal(type, doubleValue(v1) - doubleValue(v2));
696: default:
697: return newInteger(type, longValue(v1) - longValue(v2));
698: }
699: }
700:
701: public static Object multiply(Object v1, Object v2) {
702: int type = getNumericType(v1, v2);
703: switch (type) {
704: case BIGINT:
705: return bigIntValue(v1).multiply(bigIntValue(v2));
706: case BIGDEC:
707: return bigDecValue(v1).multiply(bigDecValue(v2));
708: case FLOAT:
709: case DOUBLE:
710: return newReal(type, doubleValue(v1) * doubleValue(v2));
711: default:
712: return newInteger(type, longValue(v1) * longValue(v2));
713: }
714: }
715:
716: public static Object divide(Object v1, Object v2) {
717: int type = getNumericType(v1, v2);
718: switch (type) {
719: case BIGINT:
720: return bigIntValue(v1).divide(bigIntValue(v2));
721: case BIGDEC:
722: return bigDecValue(v1).divide(bigDecValue(v2),
723: BigDecimal.ROUND_HALF_EVEN);
724: case FLOAT:
725: case DOUBLE:
726: return newReal(type, doubleValue(v1) / doubleValue(v2));
727: default:
728: return newInteger(type, longValue(v1) / longValue(v2));
729: }
730: }
731:
732: public static Object remainder(Object v1, Object v2) {
733: int type = getNumericType(v1, v2);
734: switch (type) {
735: case BIGDEC:
736: case BIGINT:
737: return bigIntValue(v1).remainder(bigIntValue(v2));
738: default:
739: return newInteger(type, longValue(v1) % longValue(v2));
740: }
741: }
742:
743: public static Object negate(Object value) {
744: int type = getNumericType(value);
745: switch (type) {
746: case BIGINT:
747: return bigIntValue(value).negate();
748: case BIGDEC:
749: return bigDecValue(value).negate();
750: case FLOAT:
751: case DOUBLE:
752: return newReal(type, -doubleValue(value));
753: default:
754: return newInteger(type, -longValue(value));
755: }
756: }
757:
758: public static Object bitNegate(Object value) {
759: int type = getNumericType(value);
760: switch (type) {
761: case BIGDEC:
762: case BIGINT:
763: return bigIntValue(value).not();
764: default:
765: return newInteger(type, ~longValue(value));
766: }
767: }
768: }
|