001/*
002 * Copyright 2002-2019 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.lang.Nullable;
026import org.springframework.util.NumberUtils;
027
028/**
029 * A basic {@link TypeComparator} implementation: supports comparison of
030 * {@link Number} types as well as types implementing {@link Comparable}.
031 *
032 * @author Andy Clement
033 * @author Juergen Hoeller
034 * @author Giovanni Dall'Oglio Risso
035 * @since 3.0
036 */
037public class StandardTypeComparator implements TypeComparator {
038
039        @Override
040        public boolean canCompare(@Nullable Object left, @Nullable Object right) {
041                if (left == null || right == null) {
042                        return true;
043                }
044                if (left instanceof Number && right instanceof Number) {
045                        return true;
046                }
047                if (left instanceof Comparable) {
048                        return true;
049                }
050                return false;
051        }
052
053        @Override
054        @SuppressWarnings("unchecked")
055        public int compare(@Nullable Object left, @Nullable Object right) throws SpelEvaluationException {
056                // If one is null, check if the other is
057                if (left == null) {
058                        return (right == null ? 0 : -1);
059                }
060                else if (right == null) {
061                        return 1;  // left cannot be null at this point
062                }
063
064                // Basic number comparisons
065                if (left instanceof Number && right instanceof Number) {
066                        Number leftNumber = (Number) left;
067                        Number rightNumber = (Number) right;
068
069                        if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
070                                BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
071                                BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
072                                return leftBigDecimal.compareTo(rightBigDecimal);
073                        }
074                        else if (leftNumber instanceof Double || rightNumber instanceof Double) {
075                                return Double.compare(leftNumber.doubleValue(), rightNumber.doubleValue());
076                        }
077                        else if (leftNumber instanceof Float || rightNumber instanceof Float) {
078                                return Float.compare(leftNumber.floatValue(), rightNumber.floatValue());
079                        }
080                        else if (leftNumber instanceof BigInteger || rightNumber instanceof BigInteger) {
081                                BigInteger leftBigInteger = NumberUtils.convertNumberToTargetClass(leftNumber, BigInteger.class);
082                                BigInteger rightBigInteger = NumberUtils.convertNumberToTargetClass(rightNumber, BigInteger.class);
083                                return leftBigInteger.compareTo(rightBigInteger);
084                        }
085                        else if (leftNumber instanceof Long || rightNumber instanceof Long) {
086                                return Long.compare(leftNumber.longValue(), rightNumber.longValue());
087                        }
088                        else if (leftNumber instanceof Integer || rightNumber instanceof Integer) {
089                                return Integer.compare(leftNumber.intValue(), rightNumber.intValue());
090                        }
091                        else if (leftNumber instanceof Short || rightNumber instanceof Short) {
092                                return Short.compare(leftNumber.shortValue(), rightNumber.shortValue());
093                        }
094                        else if (leftNumber instanceof Byte || rightNumber instanceof Byte) {
095                                return Byte.compare(leftNumber.byteValue(), rightNumber.byteValue());
096                        }
097                        else {
098                                // Unknown Number subtypes -> best guess is double multiplication
099                                return Double.compare(leftNumber.doubleValue(), rightNumber.doubleValue());
100                        }
101                }
102
103                try {
104                        if (left instanceof Comparable) {
105                                return ((Comparable<Object>) left).compareTo(right);
106                        }
107                }
108                catch (ClassCastException ex) {
109                        throw new SpelEvaluationException(ex, SpelMessage.NOT_COMPARABLE, left.getClass(), right.getClass());
110                }
111
112                throw new SpelEvaluationException(SpelMessage.NOT_COMPARABLE, left.getClass(), right.getClass());
113        }
114
115}