001/*
002 * Copyright 2002-2014 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016
017package org.springframework.expression.spel.support;
018
019import java.math.BigDecimal;
020import java.math.BigInteger;
021
022import org.springframework.expression.TypeComparator;
023import org.springframework.expression.spel.SpelEvaluationException;
024import org.springframework.expression.spel.SpelMessage;
025import org.springframework.util.NumberUtils;
026
027/**
028 * A simple basic {@link TypeComparator} implementation.
029 * It supports comparison of Numbers and types implementing Comparable.
030 *
031 * @author Andy Clement
032 * @author Juergen Hoeller
033 * @author Giovanni Dall'Oglio Risso
034 * @since 3.0
035 */
036public class StandardTypeComparator implements TypeComparator {
037
038        @Override
039        public boolean canCompare(Object left, Object right) {
040                if (left == null || right == null) {
041                        return true;
042                }
043                if (left instanceof Number && right instanceof Number) {
044                        return true;
045                }
046                if (left instanceof Comparable) {
047                        return true;
048                }
049                return false;
050        }
051
052        @Override
053        @SuppressWarnings("unchecked")
054        public int compare(Object left, Object right) throws SpelEvaluationException {
055                // If one is null, check if the other is
056                if (left == null) {
057                        return (right == null ? 0 : -1);
058                }
059                else if (right == null) {
060                        return 1;  // left cannot be null at this point
061                }
062
063                // Basic number comparisons
064                if (left instanceof Number && right instanceof Number) {
065                        Number leftNumber = (Number) left;
066                        Number rightNumber = (Number) right;
067
068                        if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
069                                BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
070                                BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
071                                return leftBigDecimal.compareTo(rightBigDecimal);
072                        }
073                        else if (leftNumber instanceof Double || rightNumber instanceof Double) {
074                                return Double.compare(leftNumber.doubleValue(), rightNumber.doubleValue());
075                        }
076                        else if (leftNumber instanceof Float || rightNumber instanceof Float) {
077                                return Float.compare(leftNumber.floatValue(), rightNumber.floatValue());
078                        }
079                        else if (leftNumber instanceof BigInteger || rightNumber instanceof BigInteger) {
080                                BigInteger leftBigInteger = NumberUtils.convertNumberToTargetClass(leftNumber, BigInteger.class);
081                                BigInteger rightBigInteger = NumberUtils.convertNumberToTargetClass(rightNumber, BigInteger.class);
082                                return leftBigInteger.compareTo(rightBigInteger);
083                        }
084                        else if (leftNumber instanceof Long || rightNumber instanceof Long) {
085                                // Don't call Long.compare here - only available on JDK 1.7+
086                                return compare(leftNumber.longValue(), rightNumber.longValue());
087                        }
088                        else if (leftNumber instanceof Integer || rightNumber instanceof Integer) {
089                                // Don't call Integer.compare here - only available on JDK 1.7+
090                                return compare(leftNumber.intValue(), rightNumber.intValue());
091                        }
092                        else if (leftNumber instanceof Short || rightNumber instanceof Short) {
093                                // Don't call Short.compare here - only available on JDK 1.7+
094                                return compare(leftNumber.shortValue(), rightNumber.shortValue());
095                        }
096                        else if (leftNumber instanceof Byte || rightNumber instanceof Byte) {
097                                // Don't call Short.compare here - only available on JDK 1.7+
098                                return compare(leftNumber.byteValue(), rightNumber.byteValue());
099                        }
100                        else {
101                                // Unknown Number subtypes -> best guess is double multiplication
102                                return Double.compare(leftNumber.doubleValue(), rightNumber.doubleValue());
103                        }
104                }
105
106                try {
107                        if (left instanceof Comparable) {
108                                return ((Comparable<Object>) left).compareTo(right);
109                        }
110                }
111                catch (ClassCastException ex) {
112                        throw new SpelEvaluationException(ex, SpelMessage.NOT_COMPARABLE, left.getClass(), right.getClass());
113                }
114
115                throw new SpelEvaluationException(SpelMessage.NOT_COMPARABLE, left.getClass(), right.getClass());
116        }
117
118
119        private static int compare(long x, long y) {
120                return (x < y ? -1 : (x > y ? 1 : 0));
121        }
122
123        private static int compare(int x, int y) {
124                return (x < y ? -1 : (x > y ? 1 : 0));
125        }
126
127        private static int compare(short x, short y) {
128                return x - y;
129        }
130
131        private static int compare(byte x, byte y) {
132                return x - y;
133        }
134
135}