View Javadoc
1   /*
2    * Copyright 2002-2014 the original author or authors.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package org.springframework.expression.spel.support;
18  
19  import java.math.BigDecimal;
20  import java.math.BigInteger;
21  
22  import org.springframework.expression.TypeComparator;
23  import org.springframework.expression.spel.SpelEvaluationException;
24  import org.springframework.expression.spel.SpelMessage;
25  import org.springframework.util.NumberUtils;
26  
27  /**
28   * A simple basic {@link TypeComparator} implementation.
29   * It supports comparison of Numbers and types implementing Comparable.
30   *
31   * @author Andy Clement
32   * @author Juergen Hoeller
33   * @author Giovanni Dall'Oglio Risso
34   * @since 3.0
35   */
36  public class StandardTypeComparator implements TypeComparator {
37  
38  	@Override
39  	public boolean canCompare(Object left, Object right) {
40  		if (left == null || right == null) {
41  			return true;
42  		}
43  		if (left instanceof Number && right instanceof Number) {
44  			return true;
45  		}
46  		if (left instanceof Comparable) {
47  			return true;
48  		}
49  		return false;
50  	}
51  
52  	@Override
53  	@SuppressWarnings("unchecked")
54  	public int compare(Object left, Object right) throws SpelEvaluationException {
55  		// If one is null, check if the other is
56  		if (left == null) {
57  			return (right == null ? 0 : -1);
58  		}
59  		else if (right == null) {
60  			return 1;  // left cannot be null at this point
61  		}
62  
63  		// Basic number comparisons
64  		if (left instanceof Number && right instanceof Number) {
65  			Number leftNumber = (Number) left;
66  			Number rightNumber = (Number) right;
67  
68  			if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
69  				BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
70  				BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
71  				return leftBigDecimal.compareTo(rightBigDecimal);
72  			}
73  			else if (leftNumber instanceof Double || rightNumber instanceof Double) {
74  				return Double.compare(leftNumber.doubleValue(), rightNumber.doubleValue());
75  			}
76  			else if (leftNumber instanceof Float || rightNumber instanceof Float) {
77  				return Float.compare(leftNumber.floatValue(), rightNumber.floatValue());
78  			}
79  			else if (leftNumber instanceof BigInteger || rightNumber instanceof BigInteger) {
80  				BigInteger leftBigInteger = NumberUtils.convertNumberToTargetClass(leftNumber, BigInteger.class);
81  				BigInteger rightBigInteger = NumberUtils.convertNumberToTargetClass(rightNumber, BigInteger.class);
82  				return leftBigInteger.compareTo(rightBigInteger);
83  			}
84  			else if (leftNumber instanceof Long || rightNumber instanceof Long) {
85  				// Don't call Long.compare here - only available on JDK 1.7+
86  				return compare(leftNumber.longValue(), rightNumber.longValue());
87  			}
88  			else if (leftNumber instanceof Integer || rightNumber instanceof Integer) {
89  				// Don't call Integer.compare here - only available on JDK 1.7+
90  				return compare(leftNumber.intValue(), rightNumber.intValue());
91  			}
92  			else if (leftNumber instanceof Short || rightNumber instanceof Short) {
93  				// Don't call Short.compare here - only available on JDK 1.7+
94  				return compare(leftNumber.shortValue(), rightNumber.shortValue());
95  			}
96  			else if (leftNumber instanceof Byte || rightNumber instanceof Byte) {
97  				// Don't call Short.compare here - only available on JDK 1.7+
98  				return compare(leftNumber.byteValue(), rightNumber.byteValue());
99  			}
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 }