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.ast;
018
019import java.math.BigDecimal;
020import java.math.BigInteger;
021
022import org.springframework.asm.MethodVisitor;
023import org.springframework.expression.EvaluationException;
024import org.springframework.expression.spel.CodeFlow;
025import org.springframework.expression.spel.ExpressionState;
026import org.springframework.expression.spel.support.BooleanTypedValue;
027import org.springframework.util.NumberUtils;
028
029/**
030 * Implements the less-than operator.
031 *
032 * @author Andy Clement
033 * @author Juergen Hoeller
034 * @author Giovanni Dall'Oglio Risso
035 * @since 3.0
036 */
037public class OpLT extends Operator {
038
039        public OpLT(int pos, SpelNodeImpl... operands) {
040                super("<", pos, operands);
041                this.exitTypeDescriptor = "Z";
042        }
043
044
045        @Override
046        public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
047                Object left = getLeftOperand().getValueInternal(state).getValue();
048                Object right = getRightOperand().getValueInternal(state).getValue();
049
050                this.leftActualDescriptor = CodeFlow.toDescriptorFromObject(left);
051                this.rightActualDescriptor = CodeFlow.toDescriptorFromObject(right);
052
053                if (left instanceof Number && right instanceof Number) {
054                        Number leftNumber = (Number) left;
055                        Number rightNumber = (Number) right;
056
057                        if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
058                                BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
059                                BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
060                                return BooleanTypedValue.forValue(leftBigDecimal.compareTo(rightBigDecimal) < 0);
061                        }
062                        else if (leftNumber instanceof Double || rightNumber instanceof Double) {
063                                return BooleanTypedValue.forValue(leftNumber.doubleValue() < rightNumber.doubleValue());
064                        }
065                        else if (leftNumber instanceof Float || rightNumber instanceof Float) {
066                                return BooleanTypedValue.forValue(leftNumber.floatValue() < rightNumber.floatValue());
067                        }
068                        else if (leftNumber instanceof BigInteger || rightNumber instanceof BigInteger) {
069                                BigInteger leftBigInteger = NumberUtils.convertNumberToTargetClass(leftNumber, BigInteger.class);
070                                BigInteger rightBigInteger = NumberUtils.convertNumberToTargetClass(rightNumber, BigInteger.class);
071                                return BooleanTypedValue.forValue(leftBigInteger.compareTo(rightBigInteger) < 0);
072                        }
073                        else if (leftNumber instanceof Long || rightNumber instanceof Long) {
074                                return BooleanTypedValue.forValue(leftNumber.longValue() < rightNumber.longValue());
075                        }
076                        else if (leftNumber instanceof Integer || rightNumber instanceof Integer) {
077                                return BooleanTypedValue.forValue(leftNumber.intValue() < rightNumber.intValue());
078                        }
079                        else if (leftNumber instanceof Short || rightNumber instanceof Short) {
080                                return BooleanTypedValue.forValue(leftNumber.shortValue() < rightNumber.shortValue());
081                        }
082                        else if (leftNumber instanceof Byte || rightNumber instanceof Byte) {
083                                return BooleanTypedValue.forValue(leftNumber.byteValue() < rightNumber.byteValue());
084                        }
085                        else {
086                                // Unknown Number subtypes -> best guess is double comparison
087                                return BooleanTypedValue.forValue(leftNumber.doubleValue() < rightNumber.doubleValue());
088                        }
089                }
090
091                if (left instanceof CharSequence && right instanceof CharSequence) {
092                        left = left.toString();
093                        right = right.toString();
094                }
095
096                return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) < 0);
097        }
098        
099        @Override
100        public boolean isCompilable() {
101                return isCompilableOperatorUsingNumerics();
102        }
103        
104        @Override
105        public void generateCode(MethodVisitor mv, CodeFlow cf) {
106                generateComparisonCode(mv, cf, IFGE, IF_ICMPGE);
107        }
108
109}