提交 d0ab131a 编写于 作者: G giovannidalloglio 提交者: Phillip Webb

Add BigDecimal support for SpEl numeric operations

Prior to this change, SpEL supported numeric operations for int, float,
ect. `new java.math.BigDecimal('0.1') > 0` evaluated to false
(BigDecimal is truncated to int)

This commit introduces support for BigDecimal operations for all
mathematical operators. `new java.math.BigDecimal('0.1') > 0` now
evaluates to true (the comparison is made with BigDecimals)

Issue: SPR-9164
上级 a4195843
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
...@@ -29,6 +31,7 @@ import org.springframework.util.Assert; ...@@ -29,6 +31,7 @@ import org.springframework.util.Assert;
* appropriate exceptions if the operand in question does not support decrement. * appropriate exceptions if the operand in question does not support decrement.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.2 * @since 3.2
*/ */
public class OpDec extends Operator { public class OpDec extends Operator {
...@@ -58,7 +61,11 @@ public class OpDec extends Operator { ...@@ -58,7 +61,11 @@ public class OpDec extends Operator {
if (operandValue instanceof Number) { if (operandValue instanceof Number) {
Number op1 = (Number) operandValue; Number op1 = (Number) operandValue;
if (op1 instanceof Double) { if (op1 instanceof BigDecimal) {
newValue = new TypedValue(((BigDecimal) op1).subtract(BigDecimal.ONE),
operandTypedValue.getTypeDescriptor());
}
else if (op1 instanceof Double) {
newValue = new TypedValue(op1.doubleValue() - 1.0d, newValue = new TypedValue(op1.doubleValue() - 1.0d,
operandTypedValue.getTypeDescriptor()); operandTypedValue.getTypeDescriptor());
} }
...@@ -79,7 +86,7 @@ public class OpDec extends Operator { ...@@ -79,7 +86,7 @@ public class OpDec extends Operator {
operandTypedValue.getTypeDescriptor()); operandTypedValue.getTypeDescriptor());
} }
} }
if (newValue==null) { if (newValue == null) {
try { try {
newValue = state.operate(Operation.SUBTRACT, returnValue.getValue(), 1); newValue = state.operate(Operation.SUBTRACT, returnValue.getValue(), 1);
} }
......
...@@ -16,20 +16,26 @@ ...@@ -16,20 +16,26 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import java.math.RoundingMode;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.NumberUtils;
/** /**
* Implements division operator. * Implements division operator.
* *
* @author Andy Clement * @author Andy Clement
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpDivide extends Operator { public class OpDivide extends Operator {
public OpDivide(int pos, SpelNodeImpl... operands) { public OpDivide(int pos, SpelNodeImpl... operands) {
super("/", pos, operands); super("/", pos, operands);
} }
...@@ -37,26 +43,35 @@ public class OpDivide extends Operator { ...@@ -37,26 +43,35 @@ public class OpDivide extends Operator {
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object operandOne = getLeftOperand().getValueInternal(state).getValue(); Object leftOperand = getLeftOperand().getValueInternal(state).getValue();
Object operandTwo = getRightOperand().getValueInternal(state).getValue(); Object rightOperand = getRightOperand().getValueInternal(state).getValue();
if (operandOne instanceof Number && operandTwo instanceof Number) {
Number op1 = (Number) operandOne; if (leftOperand instanceof Number && rightOperand instanceof Number) {
Number op2 = (Number) operandTwo; Number leftNumber = (Number) leftOperand;
if (op1 instanceof Double || op2 instanceof Double) { Number rightNumber = (Number) rightOperand;
return new TypedValue(op1.doubleValue() / op2.doubleValue());
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
int scale = Math.max(leftBigDecimal.scale(), rightBigDecimal.scale());
return new TypedValue(leftBigDecimal.divide(rightBigDecimal, scale, RoundingMode.HALF_EVEN));
} }
else if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(op1.floatValue() / op2.floatValue()); if (leftNumber instanceof Double || rightNumber instanceof Double) {
return new TypedValue(leftNumber.doubleValue() / rightNumber.doubleValue());
} }
else if (op1 instanceof Long || op2 instanceof Long) { if (leftNumber instanceof Float || rightNumber instanceof Float) {
return new TypedValue(op1.longValue() / op2.longValue()); return new TypedValue(leftNumber.floatValue() / rightNumber.floatValue());
} }
else { if (leftNumber instanceof Long || rightNumber instanceof Long) {
// TODO what about non-int result of the division? return new TypedValue(leftNumber.longValue() / rightNumber.longValue());
return new TypedValue(op1.intValue() / op2.intValue());
} }
// TODO what about non-int result of the division?
return new TypedValue(leftNumber.intValue() / rightNumber.intValue());
} }
return state.operate(Operation.DIVIDE, operandOne, operandTwo);
return state.operate(Operation.DIVIDE, leftOperand, rightOperand);
} }
} }
...@@ -15,18 +15,23 @@ ...@@ -15,18 +15,23 @@
*/ */
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;
/** /**
* Implements greater-than-or-equal operator. * Implements greater-than-or-equal operator.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpGE extends Operator { public class OpGE extends Operator {
public OpGE(int pos, SpelNodeImpl... operands) { public OpGE(int pos, SpelNodeImpl... operands) {
super(">=", pos, operands); super(">=", pos, operands);
} }
...@@ -39,18 +44,25 @@ public class OpGE extends Operator { ...@@ -39,18 +44,25 @@ public class OpGE extends Operator {
if (left instanceof Number && right instanceof Number) { if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left; Number leftNumber = (Number) left;
Number rightNumber = (Number) right; Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return BooleanTypedValue.forValue(leftBigDecimal.compareTo(rightBigDecimal) >= 0);
}
if (leftNumber instanceof Double || rightNumber instanceof Double) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
return BooleanTypedValue.forValue(leftNumber.doubleValue() >= rightNumber.doubleValue()); return BooleanTypedValue.forValue(leftNumber.doubleValue() >= rightNumber.doubleValue());
} }
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
if (leftNumber instanceof Float || rightNumber instanceof Float) {
return BooleanTypedValue.forValue(leftNumber.floatValue() >= rightNumber.floatValue()); return BooleanTypedValue.forValue(leftNumber.floatValue() >= rightNumber.floatValue());
} }
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
if (leftNumber instanceof Long || rightNumber instanceof Long) {
return BooleanTypedValue.forValue(leftNumber.longValue() >= rightNumber.longValue()); return BooleanTypedValue.forValue(leftNumber.longValue() >= rightNumber.longValue());
} }
else { return BooleanTypedValue.forValue(leftNumber.intValue() >= rightNumber.intValue());
return BooleanTypedValue.forValue(leftNumber.intValue() >= rightNumber.intValue());
}
} }
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) >= 0); return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) >= 0);
} }
......
...@@ -16,14 +16,18 @@ ...@@ -16,14 +16,18 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;
/** /**
* Implements greater-than operator. * Implements greater-than operator.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpGT extends Operator { public class OpGT extends Operator {
...@@ -38,21 +42,30 @@ public class OpGT extends Operator { ...@@ -38,21 +42,30 @@ public class OpGT extends Operator {
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException { public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue(); Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue(); Object right = getRightOperand().getValueInternal(state).getValue();
if (left instanceof Number && right instanceof Number) { if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left; Number leftNumber = (Number) left;
Number rightNumber = (Number) right; Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return BooleanTypedValue.forValue(leftBigDecimal.compareTo(rightBigDecimal) > 0);
}
if (leftNumber instanceof Double || rightNumber instanceof Double) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
return BooleanTypedValue.forValue(leftNumber.doubleValue() > rightNumber.doubleValue()); return BooleanTypedValue.forValue(leftNumber.doubleValue() > rightNumber.doubleValue());
} }
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
if (leftNumber instanceof Float || rightNumber instanceof Float) {
return BooleanTypedValue.forValue(leftNumber.floatValue() > rightNumber.floatValue()); return BooleanTypedValue.forValue(leftNumber.floatValue() > rightNumber.floatValue());
} }
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
if (leftNumber instanceof Long || rightNumber instanceof Long) {
return BooleanTypedValue.forValue(leftNumber.longValue() > rightNumber.longValue()); return BooleanTypedValue.forValue(leftNumber.longValue() > rightNumber.longValue());
} }
else {
return BooleanTypedValue.forValue(leftNumber.intValue() > rightNumber.intValue()); return BooleanTypedValue.forValue(leftNumber.intValue() > rightNumber.intValue());
}
} }
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) > 0); return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) > 0);
} }
......
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
...@@ -29,6 +31,7 @@ import org.springframework.util.Assert; ...@@ -29,6 +31,7 @@ import org.springframework.util.Assert;
* appropriate exceptions if the operand in question does not support increment. * appropriate exceptions if the operand in question does not support increment.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.2 * @since 3.2
*/ */
public class OpInc extends Operator { public class OpInc extends Operator {
...@@ -47,34 +50,38 @@ public class OpInc extends Operator { ...@@ -47,34 +50,38 @@ public class OpInc extends Operator {
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
SpelNodeImpl operand = getLeftOperand(); SpelNodeImpl operand = getLeftOperand();
ValueRef lvalue = operand.getValueRef(state); ValueRef valueRef = operand.getValueRef(state);
final TypedValue operandTypedValue = lvalue.getValue(); final TypedValue typedValue = valueRef.getValue();
final Object operandValue = operandTypedValue.getValue(); final Object value = typedValue.getValue();
TypedValue returnValue = operandTypedValue; TypedValue returnValue = typedValue;
TypedValue newValue = null; TypedValue newValue = null;
if (operandValue instanceof Number) { if (value instanceof Number) {
Number op1 = (Number) operandValue; Number op1 = (Number) value;
if (op1 instanceof Double) { if (op1 instanceof BigDecimal) {
newValue = new TypedValue(((BigDecimal) op1).add(BigDecimal.ONE),
typedValue.getTypeDescriptor());
}
else if (op1 instanceof Double) {
newValue = new TypedValue(op1.doubleValue() + 1.0d, newValue = new TypedValue(op1.doubleValue() + 1.0d,
operandTypedValue.getTypeDescriptor()); typedValue.getTypeDescriptor());
} }
else if (op1 instanceof Float) { else if (op1 instanceof Float) {
newValue = new TypedValue(op1.floatValue() + 1.0f, newValue = new TypedValue(op1.floatValue() + 1.0f,
operandTypedValue.getTypeDescriptor()); typedValue.getTypeDescriptor());
} }
else if (op1 instanceof Long) { else if (op1 instanceof Long) {
newValue = new TypedValue(op1.longValue() + 1L, newValue = new TypedValue(op1.longValue() + 1L,
operandTypedValue.getTypeDescriptor()); typedValue.getTypeDescriptor());
} }
else if (op1 instanceof Short) { else if (op1 instanceof Short) {
newValue = new TypedValue(op1.shortValue() + (short) 1, newValue = new TypedValue(op1.shortValue() + (short) 1,
operandTypedValue.getTypeDescriptor()); typedValue.getTypeDescriptor());
} }
else { else {
newValue = new TypedValue(op1.intValue() + 1, newValue = new TypedValue(op1.intValue() + 1,
operandTypedValue.getTypeDescriptor()); typedValue.getTypeDescriptor());
} }
} }
if (newValue == null) { if (newValue == null) {
...@@ -93,7 +100,7 @@ public class OpInc extends Operator { ...@@ -93,7 +100,7 @@ public class OpInc extends Operator {
// set the name value // set the name value
try { try {
lvalue.setValue(newValue.getValue()); valueRef.setValue(newValue.getValue());
} }
catch (SpelEvaluationException see) { catch (SpelEvaluationException see) {
// if unable to set the value the operand is not writable (e.g. 1++ ) // if unable to set the value the operand is not writable (e.g. 1++ )
......
...@@ -16,18 +16,23 @@ ...@@ -16,18 +16,23 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;
/** /**
* Implements the less-than-or-equal operator. * Implements the less-than-or-equal operator.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpLE extends Operator { public class OpLE extends Operator {
public OpLE(int pos, SpelNodeImpl... operands) { public OpLE(int pos, SpelNodeImpl... operands) {
super("<=", pos, operands); super("<=", pos, operands);
} }
...@@ -41,19 +46,28 @@ public class OpLE extends Operator { ...@@ -41,19 +46,28 @@ public class OpLE extends Operator {
if (left instanceof Number && right instanceof Number) { if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left; Number leftNumber = (Number) left;
Number rightNumber = (Number) right; Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return BooleanTypedValue.forValue(leftBigDecimal.compareTo(rightBigDecimal) <= 0);
}
if (leftNumber instanceof Double || rightNumber instanceof Double) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
return BooleanTypedValue.forValue(leftNumber.doubleValue() <= rightNumber.doubleValue()); return BooleanTypedValue.forValue(leftNumber.doubleValue() <= rightNumber.doubleValue());
} }
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
if (leftNumber instanceof Float || rightNumber instanceof Float) {
return BooleanTypedValue.forValue(leftNumber.floatValue() <= rightNumber.floatValue()); return BooleanTypedValue.forValue(leftNumber.floatValue() <= rightNumber.floatValue());
} }
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
if (leftNumber instanceof Long || rightNumber instanceof Long) {
return BooleanTypedValue.forValue(leftNumber.longValue() <= rightNumber.longValue()); return BooleanTypedValue.forValue(leftNumber.longValue() <= rightNumber.longValue());
} }
else {
return BooleanTypedValue.forValue(leftNumber.intValue() <= rightNumber.intValue()); return BooleanTypedValue.forValue(leftNumber.intValue() <= rightNumber.intValue());
}
} }
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) <= 0); return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) <= 0);
} }
......
...@@ -16,14 +16,18 @@ ...@@ -16,14 +16,18 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue; import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;
/** /**
* Implements the less-than operator. * Implements the less-than operator.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpLT extends Operator { public class OpLT extends Operator {
...@@ -43,18 +47,26 @@ public class OpLT extends Operator { ...@@ -43,18 +47,26 @@ public class OpLT extends Operator {
if (left instanceof Number && right instanceof Number) { if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left; Number leftNumber = (Number) left;
Number rightNumber = (Number) right; Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return BooleanTypedValue.forValue(leftBigDecimal.compareTo(rightBigDecimal) < 0);
}
if (leftNumber instanceof Double || rightNumber instanceof Double) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
return BooleanTypedValue.forValue(leftNumber.doubleValue() < rightNumber.doubleValue()); return BooleanTypedValue.forValue(leftNumber.doubleValue() < rightNumber.doubleValue());
} }
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
if (leftNumber instanceof Float || rightNumber instanceof Float) {
return BooleanTypedValue.forValue(leftNumber.floatValue() < rightNumber.floatValue()); return BooleanTypedValue.forValue(leftNumber.floatValue() < rightNumber.floatValue());
} }
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
if (leftNumber instanceof Long || rightNumber instanceof Long) {
return BooleanTypedValue.forValue(leftNumber.longValue() < rightNumber.longValue()); return BooleanTypedValue.forValue(leftNumber.longValue() < rightNumber.longValue());
} }
else {
return BooleanTypedValue.forValue(leftNumber.intValue() < rightNumber.intValue()); return BooleanTypedValue.forValue(leftNumber.intValue() < rightNumber.intValue());
}
} }
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) < 0); return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) < 0);
} }
......
...@@ -16,33 +16,40 @@ ...@@ -16,33 +16,40 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.NumberUtils;
/** /**
* The minus operator supports: * The minus operator supports:
* <ul> * <ul>
* <li>subtraction of {@code BigDecimal}
* <li>subtraction of doubles (floats are represented as doubles) * <li>subtraction of doubles (floats are represented as doubles)
* <li>subtraction of longs * <li>subtraction of longs
* <li>subtraction of integers * <li>subtraction of integers
* <li>subtraction of an int from a string of one character (effectively decreasing that * <li>subtraction of an int from a string of one character (effectively decreasing that
* character), so 'd'-3='a' * character), so 'd'-3='a'
* </ul> * </ul>
* It can be used as a unary operator for numbers (double/long/int). The standard * It can be used as a unary operator for numbers ({@code BigDecimal}/double/long/int).
* promotions are performed when the operand types vary (double-int=double). For other * The standard promotions are performed when the operand types vary (double-int=double).
* options it defers to the registered overloader. * For other options it defers to the registered overloader.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpMinus extends Operator { public class OpMinus extends Operator {
public OpMinus(int pos, SpelNodeImpl... operands) { public OpMinus(int pos, SpelNodeImpl... operands) {
super("-", pos, operands); super("-", pos, operands);
} }
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
...@@ -53,6 +60,12 @@ public class OpMinus extends Operator { ...@@ -53,6 +60,12 @@ public class OpMinus extends Operator {
Object operand = leftOp.getValueInternal(state).getValue(); Object operand = leftOp.getValueInternal(state).getValue();
if (operand instanceof Number) { if (operand instanceof Number) {
Number n = (Number) operand; Number n = (Number) operand;
if (operand instanceof BigDecimal) {
BigDecimal bdn = (BigDecimal) n;
return new TypedValue(bdn.negate());
}
if (operand instanceof Double) { if (operand instanceof Double) {
return new TypedValue(0 - n.doubleValue()); return new TypedValue(0 - n.doubleValue());
} }
...@@ -64,6 +77,7 @@ public class OpMinus extends Operator { ...@@ -64,6 +77,7 @@ public class OpMinus extends Operator {
if (operand instanceof Long) { if (operand instanceof Long) {
return new TypedValue(0 - n.longValue()); return new TypedValue(0 - n.longValue());
} }
return new TypedValue(0 - n.intValue()); return new TypedValue(0 - n.intValue());
} }
...@@ -74,21 +88,28 @@ public class OpMinus extends Operator { ...@@ -74,21 +88,28 @@ public class OpMinus extends Operator {
Object right = rightOp.getValueInternal(state).getValue(); Object right = rightOp.getValueInternal(state).getValue();
if (left instanceof Number && right instanceof Number) { if (left instanceof Number && right instanceof Number) {
Number op1 = (Number) left; Number leftNumber = (Number) left;
Number op2 = (Number) right; Number rightNumber = (Number) right;
if (op1 instanceof Double || op2 instanceof Double) {
return new TypedValue(op1.doubleValue() - op2.doubleValue()); if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return new TypedValue(leftBigDecimal.subtract(rightBigDecimal));
}
if (leftNumber instanceof Double || rightNumber instanceof Double) {
return new TypedValue(leftNumber.doubleValue() - rightNumber.doubleValue());
} }
if (op1 instanceof Float || op2 instanceof Float) { if (leftNumber instanceof Float || rightNumber instanceof Float) {
return new TypedValue(op1.floatValue() - op2.floatValue()); return new TypedValue(leftNumber.floatValue() - rightNumber.floatValue());
} }
if (op1 instanceof Long || op2 instanceof Long) { if (leftNumber instanceof Long || rightNumber instanceof Long) {
return new TypedValue(op1.longValue() - op2.longValue()); return new TypedValue(leftNumber.longValue() - rightNumber.longValue());
} }
return new TypedValue(op1.intValue() - op2.intValue()); return new TypedValue(leftNumber.intValue() - rightNumber.intValue());
} }
else if (left instanceof String && right instanceof Integer else if (left instanceof String && right instanceof Integer
&& ((String) left).length() == 1) { && ((String) left).length() == 1) {
......
...@@ -16,19 +16,24 @@ ...@@ -16,19 +16,24 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.NumberUtils;
/** /**
* Implements the modulus operator. * Implements the modulus operator.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpModulus extends Operator { public class OpModulus extends Operator {
public OpModulus(int pos, SpelNodeImpl... operands) { public OpModulus(int pos, SpelNodeImpl... operands) {
super("%", pos, operands); super("%", pos, operands);
} }
...@@ -36,25 +41,34 @@ public class OpModulus extends Operator { ...@@ -36,25 +41,34 @@ public class OpModulus extends Operator {
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object operandOne = getLeftOperand().getValueInternal(state).getValue(); Object leftOperand = getLeftOperand().getValueInternal(state).getValue();
Object operandTwo = getRightOperand().getValueInternal(state).getValue(); Object rightOperand = getRightOperand().getValueInternal(state).getValue();
if (operandOne instanceof Number && operandTwo instanceof Number) { if (leftOperand instanceof Number && rightOperand instanceof Number) {
Number op1 = (Number) operandOne; Number leftNumber = (Number) leftOperand;
Number op2 = (Number) operandTwo; Number rightNumber = (Number) rightOperand;
if (op1 instanceof Double || op2 instanceof Double) {
return new TypedValue(op1.doubleValue() % op2.doubleValue()); if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return new TypedValue(leftBigDecimal.remainder(rightBigDecimal));
} }
else if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(op1.floatValue() % op2.floatValue()); if (leftNumber instanceof Double || rightNumber instanceof Double) {
return new TypedValue(leftNumber.doubleValue() % rightNumber.doubleValue());
} }
else if (op1 instanceof Long || op2 instanceof Long) {
return new TypedValue(op1.longValue() % op2.longValue()); if (leftNumber instanceof Float || rightNumber instanceof Float) {
return new TypedValue(leftNumber.floatValue() % rightNumber.floatValue());
} }
else {
return new TypedValue(op1.intValue() % op2.intValue()); if (leftNumber instanceof Long || rightNumber instanceof Long) {
return new TypedValue(leftNumber.longValue() % rightNumber.longValue());
} }
return new TypedValue(leftNumber.intValue() % rightNumber.intValue());
} }
return state.operate(Operation.MODULUS, operandOne, operandTwo);
return state.operate(Operation.MODULUS, leftOperand, rightOperand);
} }
} }
...@@ -16,20 +16,24 @@ ...@@ -16,20 +16,24 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.NumberUtils;
/** /**
* Implements the {@code multiply} operator. * Implements the {@code multiply} operator.
* *
* <p>Conversions and promotions are handled as defined in * <p>Conversions and promotions are handled as defined in
* <a href="http://java.sun.com/docs/books/jls/third_edition/html/conversions.html">Section * <a href="http://java.sun.com/docs/books/jls/third_edition/html/conversions.html">Section
* 5.6.2 of the Java Language Specification</a>: * 5.6.2 of the Java Language Specification</a>, with the addiction of {@code BigDecimal} management:
* *
* <p>If any of the operands is of a reference type, unboxing conversion (Section 5.1.8) * <p>If any of the operands is of a reference type, unboxing conversion (Section 5.1.8)
* is performed. Then:<br> * is performed. Then:<br>
* If either operand is of type {@code BigDecimal}, the other is converted to {@code BigDecimal}.<br>
* If either operand is of type double, the other is converted to double.<br> * If either operand is of type double, the other is converted to double.<br>
* Otherwise, if either operand is of type float, the other is converted to float.<br> * Otherwise, if either operand is of type float, the other is converted to float.<br>
* Otherwise, if either operand is of type long, the other is converted to long.<br> * Otherwise, if either operand is of type long, the other is converted to long.<br>
...@@ -37,10 +41,12 @@ import org.springframework.expression.spel.ExpressionState; ...@@ -37,10 +41,12 @@ import org.springframework.expression.spel.ExpressionState;
* *
* @author Andy Clement * @author Andy Clement
* @author Sam Brannen * @author Sam Brannen
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpMultiply extends Operator { public class OpMultiply extends Operator {
public OpMultiply(int pos, SpelNodeImpl... operands) { public OpMultiply(int pos, SpelNodeImpl... operands) {
super("*", pos, operands); super("*", pos, operands);
} }
...@@ -52,6 +58,7 @@ public class OpMultiply extends Operator { ...@@ -52,6 +58,7 @@ public class OpMultiply extends Operator {
* for types not supported here. * for types not supported here.
* <p>Supported operand types: * <p>Supported operand types:
* <ul> * <ul>
* <li>{@code BigDecimal}
* <li>doubles * <li>doubles
* <li>longs * <li>longs
* <li>integers * <li>integers
...@@ -61,15 +68,20 @@ public class OpMultiply extends Operator { ...@@ -61,15 +68,20 @@ public class OpMultiply extends Operator {
@Override @Override
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException { public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object operandOne = getLeftOperand().getValueInternal(state).getValue(); Object leftOperand = getLeftOperand().getValueInternal(state).getValue();
Object operandTwo = getRightOperand().getValueInternal(state).getValue(); Object rightOperand = getRightOperand().getValueInternal(state).getValue();
if (leftOperand instanceof Number && rightOperand instanceof Number) {
Number leftNumber = (Number) leftOperand;
Number rightNumber = (Number) rightOperand;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return new TypedValue(leftBigDecimal.multiply(rightBigDecimal));
}
if (operandOne instanceof Number && operandTwo instanceof Number) {
Number leftNumber = (Number) operandOne;
Number rightNumber = (Number) operandTwo;
if (leftNumber instanceof Double || rightNumber instanceof Double) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
return new TypedValue(leftNumber.doubleValue() return new TypedValue(leftNumber.doubleValue() * rightNumber.doubleValue());
* rightNumber.doubleValue());
} }
if (leftNumber instanceof Float || rightNumber instanceof Float) { if (leftNumber instanceof Float || rightNumber instanceof Float) {
...@@ -82,16 +94,16 @@ public class OpMultiply extends Operator { ...@@ -82,16 +94,16 @@ public class OpMultiply extends Operator {
return new TypedValue(leftNumber.intValue() * rightNumber.intValue()); return new TypedValue(leftNumber.intValue() * rightNumber.intValue());
} }
else if (operandOne instanceof String && operandTwo instanceof Integer) { else if (leftOperand instanceof String && rightOperand instanceof Integer) {
int repeats = (Integer) operandTwo; int repeats = (Integer) rightOperand;
StringBuilder result = new StringBuilder(); StringBuilder result = new StringBuilder();
for (int i = 0; i < repeats; i++) { for (int i = 0; i < repeats; i++) {
result.append(operandOne); result.append(leftOperand);
} }
return new TypedValue(result.toString()); return new TypedValue(result.toString());
} }
return state.operate(Operation.MULTIPLY, operandOne, operandTwo); return state.operate(Operation.MULTIPLY, leftOperand, rightOperand);
} }
} }
...@@ -16,6 +16,8 @@ ...@@ -16,6 +16,8 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.core.convert.TypeDescriptor; import org.springframework.core.convert.TypeDescriptor;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
...@@ -23,25 +25,29 @@ import org.springframework.expression.TypeConverter; ...@@ -23,25 +25,29 @@ import org.springframework.expression.TypeConverter;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.NumberUtils;
/** /**
* The plus operator will: * The plus operator will:
* <ul> * <ul>
* <li>add {@code BigDecimal}
* <li>add doubles (floats are represented as doubles) * <li>add doubles (floats are represented as doubles)
* <li>add longs * <li>add longs
* <li>add integers * <li>add integers
* <li>concatenate strings * <li>concatenate strings
* </ul> * </ul>
* It can be used as a unary operator for numbers (double/long/int). The standard * It can be used as a unary operator for numbers ({@code BigDecimal}/double/long/int).
* promotions are performed when the operand types vary (double+int=double). For other * The standard promotions are performed when the operand types vary (double+int=double).
* options it defers to the registered overloader. * For other options it defers to the registered overloader.
* *
* @author Andy Clement * @author Andy Clement
* @author Ivo Smid * @author Ivo Smid
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OpPlus extends Operator { public class OpPlus extends Operator {
public OpPlus(int pos, SpelNodeImpl... operands) { public OpPlus(int pos, SpelNodeImpl... operands) {
super("+", pos, operands); super("+", pos, operands);
Assert.notEmpty(operands); Assert.notEmpty(operands);
...@@ -56,7 +62,7 @@ public class OpPlus extends Operator { ...@@ -56,7 +62,7 @@ public class OpPlus extends Operator {
if (rightOp == null) { // If only one operand, then this is unary plus if (rightOp == null) { // If only one operand, then this is unary plus
Object operandOne = leftOp.getValueInternal(state).getValue(); Object operandOne = leftOp.getValueInternal(state).getValue();
if (operandOne instanceof Number) { if (operandOne instanceof Number) {
if (operandOne instanceof Double || operandOne instanceof Long) { if (operandOne instanceof Double || operandOne instanceof Long || operandOne instanceof BigDecimal) {
return new TypedValue(operandOne); return new TypedValue(operandOne);
} }
if (operandOne instanceof Float) { if (operandOne instanceof Float) {
...@@ -68,47 +74,57 @@ public class OpPlus extends Operator { ...@@ -68,47 +74,57 @@ public class OpPlus extends Operator {
} }
final TypedValue operandOneValue = leftOp.getValueInternal(state); final TypedValue operandOneValue = leftOp.getValueInternal(state);
final Object operandOne = operandOneValue.getValue(); final Object leftOperand = operandOneValue.getValue();
final TypedValue operandTwoValue = rightOp.getValueInternal(state); final TypedValue operandTwoValue = rightOp.getValueInternal(state);
final Object operandTwo = operandTwoValue.getValue(); final Object rightOperand = operandTwoValue.getValue();
if (leftOperand instanceof Number && rightOperand instanceof Number) {
Number leftNumber = (Number) leftOperand;
Number rightNumber = (Number) rightOperand;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return new TypedValue(leftBigDecimal.add(rightBigDecimal));
}
if (operandOne instanceof Number && operandTwo instanceof Number) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
Number op1 = (Number) operandOne; return new TypedValue(leftNumber.doubleValue() + rightNumber.doubleValue());
Number op2 = (Number) operandTwo;
if (op1 instanceof Double || op2 instanceof Double) {
return new TypedValue(op1.doubleValue() + op2.doubleValue());
} }
if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(op1.floatValue() + op2.floatValue()); if (leftNumber instanceof Float || rightNumber instanceof Float) {
return new TypedValue(leftNumber.floatValue() + rightNumber.floatValue());
} }
if (op1 instanceof Long || op2 instanceof Long) {
return new TypedValue(op1.longValue() + op2.longValue()); if (leftNumber instanceof Long || rightNumber instanceof Long) {
return new TypedValue(leftNumber.longValue() + rightNumber.longValue());
} }
// TODO what about overflow? // TODO what about overflow?
return new TypedValue(op1.intValue() + op2.intValue()); return new TypedValue(leftNumber.intValue() + rightNumber.intValue());
} }
if (operandOne instanceof String && operandTwo instanceof String) { if (leftOperand instanceof String && rightOperand instanceof String) {
return new TypedValue(new StringBuilder((String) operandOne).append( return new TypedValue(new StringBuilder((String) leftOperand).append(
(String) operandTwo).toString()); (String) rightOperand).toString());
} }
if (operandOne instanceof String) { if (leftOperand instanceof String) {
StringBuilder result = new StringBuilder((String) operandOne); StringBuilder result = new StringBuilder((String) leftOperand);
result.append((operandTwo == null ? "null" : convertTypedValueToString( result.append((rightOperand == null ? "null" : convertTypedValueToString(
operandTwoValue, state))); operandTwoValue, state)));
return new TypedValue(result.toString()); return new TypedValue(result.toString());
} }
if (operandTwo instanceof String) { if (rightOperand instanceof String) {
StringBuilder result = new StringBuilder((operandOne == null ? "null" StringBuilder result = new StringBuilder((leftOperand == null ? "null"
: convertTypedValueToString(operandOneValue, state))); : convertTypedValueToString(operandOneValue, state)));
result.append((String) operandTwo); result.append((String) rightOperand);
return new TypedValue(result.toString()); return new TypedValue(result.toString());
} }
return state.operate(Operation.ADD, operandOne, operandTwo); return state.operate(Operation.ADD, leftOperand, rightOperand);
} }
@Override @Override
...@@ -116,7 +132,6 @@ public class OpPlus extends Operator { ...@@ -116,7 +132,6 @@ public class OpPlus extends Operator {
if (this.children.length<2) { // unary plus if (this.children.length<2) { // unary plus
return new StringBuilder().append("+").append(getLeftOperand().toStringAST()).toString(); return new StringBuilder().append("+").append(getLeftOperand().toStringAST()).toString();
} }
return super.toStringAST(); return super.toStringAST();
} }
...@@ -125,7 +140,6 @@ public class OpPlus extends Operator { ...@@ -125,7 +140,6 @@ public class OpPlus extends Operator {
if (this.children.length < 2) { if (this.children.length < 2) {
return null; return null;
} }
return this.children[1]; return this.children[1];
} }
......
...@@ -16,7 +16,11 @@ ...@@ -16,7 +16,11 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.NumberUtils;
import org.springframework.util.ObjectUtils;
/** /**
* Common supertype for operators that operate on either one or two operands. In the case * Common supertype for operators that operate on either one or two operands. In the case
...@@ -24,6 +28,7 @@ import org.springframework.expression.spel.ExpressionState; ...@@ -24,6 +28,7 @@ import org.springframework.expression.spel.ExpressionState;
* is only one. * is only one.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public abstract class Operator extends SpelNodeImpl { public abstract class Operator extends SpelNodeImpl {
...@@ -67,29 +72,35 @@ public abstract class Operator extends SpelNodeImpl { ...@@ -67,29 +72,35 @@ public abstract class Operator extends SpelNodeImpl {
protected boolean equalityCheck(ExpressionState state, Object left, Object right) { protected boolean equalityCheck(ExpressionState state, Object left, Object right) {
if (left instanceof Number && right instanceof Number) { if (left instanceof Number && right instanceof Number) {
Number op1 = (Number) left; Number leftNumber = (Number) left;
Number op2 = (Number) right; Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return (leftBigDecimal == null ? rightBigDecimal == null : leftBigDecimal.compareTo(rightBigDecimal) == 0);
}
if (op1 instanceof Double || op2 instanceof Double) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
return (op1.doubleValue() == op2.doubleValue()); return (leftNumber.doubleValue() == rightNumber.doubleValue());
} }
if (op1 instanceof Float || op2 instanceof Float) { if (leftNumber instanceof Float || rightNumber instanceof Float) {
return (op1.floatValue() == op2.floatValue()); return (leftNumber.floatValue() == rightNumber.floatValue());
} }
if (op1 instanceof Long || op2 instanceof Long) { if (leftNumber instanceof Long || rightNumber instanceof Long) {
return (op1.longValue() == op2.longValue()); return (leftNumber.longValue() == rightNumber.longValue());
} }
return (op1.intValue() == op2.intValue()); return (leftNumber.intValue() == rightNumber.intValue());
} }
if (left != null && (left instanceof Comparable)) { if (left != null && (left instanceof Comparable)) {
return (state.getTypeComparator().compare(left, right) == 0); return (state.getTypeComparator().compare(left, right) == 0);
} }
return (left == null ? right == null : left.equals(right)); return ObjectUtils.nullSafeEquals(left, right);
} }
} }
...@@ -16,15 +16,19 @@ ...@@ -16,15 +16,19 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.Operation; import org.springframework.expression.Operation;
import org.springframework.expression.TypedValue; import org.springframework.expression.TypedValue;
import org.springframework.expression.spel.ExpressionState; import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.NumberUtils;
/** /**
* The power operator. * The power operator.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class OperatorPower extends Operator { public class OperatorPower extends Operator {
...@@ -39,32 +43,41 @@ public class OperatorPower extends Operator { ...@@ -39,32 +43,41 @@ public class OperatorPower extends Operator {
SpelNodeImpl leftOp = getLeftOperand(); SpelNodeImpl leftOp = getLeftOperand();
SpelNodeImpl rightOp = getRightOperand(); SpelNodeImpl rightOp = getRightOperand();
Object operandOne = leftOp.getValueInternal(state).getValue(); Object leftOperand = leftOp.getValueInternal(state).getValue();
Object operandTwo = rightOp.getValueInternal(state).getValue(); Object rightOperand = rightOp.getValueInternal(state).getValue();
if (operandOne instanceof Number && operandTwo instanceof Number) {
Number op1 = (Number) operandOne; if (leftOperand instanceof Number && rightOperand instanceof Number) {
Number op2 = (Number) operandTwo; Number leftNumber = (Number) leftOperand;
if (op1 instanceof Double || op2 instanceof Double) { Number rightNumber = (Number) rightOperand;
return new TypedValue(Math.pow(op1.doubleValue(), op2.doubleValue()));
if (leftNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
return new TypedValue(leftBigDecimal.pow(rightNumber.intValue()));
} }
else if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(Math.pow(op1.floatValue(), op2.floatValue())); if (leftNumber instanceof Double || rightNumber instanceof Double) {
return new TypedValue(Math.pow(leftNumber.doubleValue(), rightNumber.doubleValue()));
}
if (leftNumber instanceof Float || rightNumber instanceof Float) {
return new TypedValue(Math.pow(leftNumber.floatValue(), rightNumber.floatValue()));
} }
else if (op1 instanceof Long || op2 instanceof Long) {
double d = Math.pow(op1.longValue(), op2.longValue()); if (leftNumber instanceof Long || rightNumber instanceof Long) {
double d = Math.pow(leftNumber.longValue(), rightNumber.longValue());
return new TypedValue((long) d);
}
double d = Math.pow(leftNumber.longValue(), rightNumber.longValue());
if (d > Integer.MAX_VALUE) {
return new TypedValue((long) d); return new TypedValue((long) d);
} }
else { else {
double d = Math.pow(op1.longValue(), op2.longValue()); return new TypedValue((int) d);
if (d > Integer.MAX_VALUE) {
return new TypedValue((long) d);
}
else {
return new TypedValue((int) d);
}
} }
} }
return state.operate(Operation.POWER, operandOne, operandTwo);
return state.operate(Operation.POWER, leftOperand, rightOperand);
} }
} }
...@@ -16,9 +16,12 @@ ...@@ -16,9 +16,12 @@
package org.springframework.expression.spel.support; package org.springframework.expression.spel.support;
import java.math.BigDecimal;
import org.springframework.expression.TypeComparator; import org.springframework.expression.TypeComparator;
import org.springframework.expression.spel.SpelEvaluationException; import org.springframework.expression.spel.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage; import org.springframework.expression.spel.SpelMessage;
import org.springframework.util.NumberUtils;
/** /**
* A simple basic TypeComparator implementation. It supports comparison of numbers and * A simple basic TypeComparator implementation. It supports comparison of numbers and
...@@ -26,6 +29,7 @@ import org.springframework.expression.spel.SpelMessage; ...@@ -26,6 +29,7 @@ import org.springframework.expression.spel.SpelMessage;
* *
* @author Andy Clement * @author Andy Clement
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class StandardTypeComparator implements TypeComparator { public class StandardTypeComparator implements TypeComparator {
...@@ -45,27 +49,26 @@ public class StandardTypeComparator implements TypeComparator { ...@@ -45,27 +49,26 @@ public class StandardTypeComparator implements TypeComparator {
if (left instanceof Number && right instanceof Number) { if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left; Number leftNumber = (Number) left;
Number rightNumber = (Number) right; Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return leftBigDecimal.compareTo(rightBigDecimal);
}
if (leftNumber instanceof Double || rightNumber instanceof Double) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
double d1 = leftNumber.doubleValue(); return Double.compare(leftNumber.doubleValue(), rightNumber.doubleValue());
double d2 = rightNumber.doubleValue();
return Double.compare(d1, d2);
} }
if (leftNumber instanceof Float || rightNumber instanceof Float) { if (leftNumber instanceof Float || rightNumber instanceof Float) {
float f1 = leftNumber.floatValue(); return Float.compare(leftNumber.floatValue(), rightNumber.floatValue());
float f2 = rightNumber.floatValue();
return Float.compare(f1, f2);
} }
if (leftNumber instanceof Long || rightNumber instanceof Long) { if (leftNumber instanceof Long || rightNumber instanceof Long) {
Long l1 = leftNumber.longValue(); return Long.compare(leftNumber.longValue(), rightNumber.longValue());
Long l2 = rightNumber.longValue();
return l1.compareTo(l2);
} }
Integer i1 = leftNumber.intValue(); return Integer.compare(leftNumber.intValue(), rightNumber.intValue());
Integer i2 = rightNumber.intValue();
return i1.compareTo(i2);
} }
try { try {
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -18,6 +18,8 @@ package org.springframework.expression.spel; ...@@ -18,6 +18,8 @@ package org.springframework.expression.spel;
import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue; import static org.junit.Assert.assertTrue;
import java.math.BigDecimal;
import org.junit.Test; import org.junit.Test;
import org.springframework.expression.EvaluationException; import org.springframework.expression.EvaluationException;
import org.springframework.expression.TypeComparator; import org.springframework.expression.TypeComparator;
...@@ -27,6 +29,7 @@ import org.springframework.expression.spel.support.StandardTypeComparator; ...@@ -27,6 +29,7 @@ import org.springframework.expression.spel.support.StandardTypeComparator;
* Unit tests for type comparison * Unit tests for type comparison
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
*/ */
public class DefaultComparatorUnitTests { public class DefaultComparatorUnitTests {
...@@ -59,6 +62,35 @@ public class DefaultComparatorUnitTests { ...@@ -59,6 +62,35 @@ public class DefaultComparatorUnitTests {
assertTrue(comparator.compare(2L, 1L) > 0); assertTrue(comparator.compare(2L, 1L) > 0);
} }
@Test
public void testNonPrimitiveNumbers() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator();
BigDecimal bdOne = new BigDecimal("1");
BigDecimal bdTwo = new BigDecimal("2");
assertTrue(comparator.compare(bdOne, bdTwo) < 0);
assertTrue(comparator.compare(bdOne, new BigDecimal("1")) == 0);
assertTrue(comparator.compare(bdTwo, bdOne) > 0);
assertTrue(comparator.compare(1, bdTwo) < 0);
assertTrue(comparator.compare(1, bdOne) == 0);
assertTrue(comparator.compare(2, bdOne) > 0);
assertTrue(comparator.compare(1.0d, bdTwo) < 0);
assertTrue(comparator.compare(1.0d, bdOne) == 0);
assertTrue(comparator.compare(2.0d, bdOne) > 0);
assertTrue(comparator.compare(1.0f, bdTwo) < 0);
assertTrue(comparator.compare(1.0f, bdOne) == 0);
assertTrue(comparator.compare(2.0f, bdOne) > 0);
assertTrue(comparator.compare(1L, bdTwo) < 0);
assertTrue(comparator.compare(1L, bdOne) == 0);
assertTrue(comparator.compare(2L, bdOne) > 0);
}
@Test @Test
public void testNulls() throws EvaluationException { public void testNulls() throws EvaluationException {
TypeComparator comparator = new StandardTypeComparator(); TypeComparator comparator = new StandardTypeComparator();
......
...@@ -26,6 +26,7 @@ import static org.junit.Assert.assertTrue; ...@@ -26,6 +26,7 @@ import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail; import static org.junit.Assert.fail;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -55,6 +56,7 @@ import org.springframework.expression.spel.testresources.TestPerson; ...@@ -55,6 +56,7 @@ import org.springframework.expression.spel.testresources.TestPerson;
* @author Mark Fisher * @author Mark Fisher
* @author Sam Brannen * @author Sam Brannen
* @author Phillip Webb * @author Phillip Webb
* @author Giovanni Dall'Oglio Risso
* @since 3.0 * @since 3.0
*/ */
public class EvaluationTests extends ExpressionTestCase { public class EvaluationTests extends ExpressionTestCase {
...@@ -636,6 +638,7 @@ public class EvaluationTests extends ExpressionTestCase { ...@@ -636,6 +638,7 @@ public class EvaluationTests extends ExpressionTestCase {
static class Spr9751 { static class Spr9751 {
public String type = "hello"; public String type = "hello";
public BigDecimal bd = new BigDecimal("2");
public double ddd = 2.0d; public double ddd = 2.0d;
public float fff = 3.0f; public float fff = 3.0f;
public long lll = 66666L; public long lll = 66666L;
...@@ -755,6 +758,13 @@ public class EvaluationTests extends ExpressionTestCase { ...@@ -755,6 +758,13 @@ public class EvaluationTests extends ExpressionTestCase {
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expression e = null; Expression e = null;
// BigDecimal
e = parser.parseExpression("bd++");
assertTrue(new BigDecimal("2").equals(helper.bd));
BigDecimal return_bd = e.getValue(ctx,BigDecimal.class);
assertTrue(new BigDecimal("2").equals(return_bd));
assertTrue(new BigDecimal("3").equals(helper.bd));
// double // double
e = parser.parseExpression("ddd++"); e = parser.parseExpression("ddd++");
assertEquals(2.0d,helper.ddd,0d); assertEquals(2.0d,helper.ddd,0d);
...@@ -801,6 +811,14 @@ public class EvaluationTests extends ExpressionTestCase { ...@@ -801,6 +811,14 @@ public class EvaluationTests extends ExpressionTestCase {
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expression e = null; Expression e = null;
// BigDecimal
e = parser.parseExpression("++bd");
assertTrue(new BigDecimal("2").equals(helper.bd));
BigDecimal return_bd = e.getValue(ctx,BigDecimal.class);
assertTrue(new BigDecimal("3").equals(return_bd));
assertTrue(new BigDecimal("3").equals(helper.bd));
// double // double
e = parser.parseExpression("++ddd"); e = parser.parseExpression("++ddd");
assertEquals(2.0d,helper.ddd,0d); assertEquals(2.0d,helper.ddd,0d);
...@@ -907,6 +925,13 @@ public class EvaluationTests extends ExpressionTestCase { ...@@ -907,6 +925,13 @@ public class EvaluationTests extends ExpressionTestCase {
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expression e = null; Expression e = null;
// BigDecimal
e = parser.parseExpression("bd--");
assertTrue(new BigDecimal("2").equals(helper.bd));
BigDecimal return_bd = e.getValue(ctx,BigDecimal.class);
assertTrue(new BigDecimal("2").equals(return_bd));
assertTrue(new BigDecimal("1").equals(helper.bd));
// double // double
e = parser.parseExpression("ddd--"); e = parser.parseExpression("ddd--");
assertEquals(2.0d,helper.ddd,0d); assertEquals(2.0d,helper.ddd,0d);
...@@ -953,6 +978,13 @@ public class EvaluationTests extends ExpressionTestCase { ...@@ -953,6 +978,13 @@ public class EvaluationTests extends ExpressionTestCase {
ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true)); ExpressionParser parser = new SpelExpressionParser(new SpelParserConfiguration(true, true));
Expression e = null; Expression e = null;
// BigDecimal
e = parser.parseExpression("--bd");
assertTrue(new BigDecimal("2").equals(helper.bd));
BigDecimal return_bd = e.getValue(ctx,BigDecimal.class);
assertTrue(new BigDecimal("1").equals(return_bd));
assertTrue(new BigDecimal("1").equals(helper.bd));
// double // double
e = parser.parseExpression("--ddd"); e = parser.parseExpression("--ddd");
assertEquals(2.0d,helper.ddd,0d); assertEquals(2.0d,helper.ddd,0d);
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -28,6 +28,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser; ...@@ -28,6 +28,7 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
* Test usage of inline lists. * Test usage of inline lists.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
* @since 3.0.4 * @since 3.0.4
*/ */
public class ListTests extends ExpressionTestCase { public class ListTests extends ExpressionTestCase {
...@@ -108,6 +109,14 @@ public class ListTests extends ExpressionTestCase { ...@@ -108,6 +109,14 @@ public class ListTests extends ExpressionTestCase {
evaluate("42 between {32, 42}", "true", Boolean.class); evaluate("42 between {32, 42}", "true", Boolean.class);
} }
@Test
public void testRelOperatorsBetween04() {
evaluate("new java.math.BigDecimal('1') between {new java.math.BigDecimal('1'),new java.math.BigDecimal('5')}", "true", Boolean.class);
evaluate("new java.math.BigDecimal('3') between {new java.math.BigDecimal('1'),new java.math.BigDecimal('5')}", "true", Boolean.class);
evaluate("new java.math.BigDecimal('5') between {new java.math.BigDecimal('1'),new java.math.BigDecimal('5')}", "true", Boolean.class);
evaluate("new java.math.BigDecimal('8') between {new java.math.BigDecimal('1'),new java.math.BigDecimal('5')}", "false", Boolean.class);
}
@Test @Test
public void testRelOperatorsBetweenErrors02() { public void testRelOperatorsBetweenErrors02() {
evaluateAndCheckError("'abc' between {5,7}", SpelMessage.NOT_COMPARABLE, 6); evaluateAndCheckError("'abc' between {5,7}", SpelMessage.NOT_COMPARABLE, 6);
......
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2013 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
package org.springframework.expression.spel; package org.springframework.expression.spel;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import java.math.BigDecimal;
import org.junit.Test; import org.junit.Test;
import org.springframework.expression.spel.ast.Operator; import org.springframework.expression.spel.ast.Operator;
...@@ -26,6 +27,7 @@ import org.springframework.expression.spel.standard.SpelExpression; ...@@ -26,6 +27,7 @@ import org.springframework.expression.spel.standard.SpelExpression;
* Tests the evaluation of expressions using relational operators. * Tests the evaluation of expressions using relational operators.
* *
* @author Andy Clement * @author Andy Clement
* @author Giovanni Dall'Oglio Risso
*/ */
public class OperatorTests extends ExpressionTestCase { public class OperatorTests extends ExpressionTestCase {
...@@ -41,6 +43,8 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -41,6 +43,8 @@ public class OperatorTests extends ExpressionTestCase {
@Test @Test
public void testLessThan() { public void testLessThan() {
evaluate("5 < 5", false, Boolean.class);
evaluate("3 < 5", true, Boolean.class); evaluate("3 < 5", true, Boolean.class);
evaluate("5 < 3", false, Boolean.class); evaluate("5 < 3", false, Boolean.class);
evaluate("3L < 5L", true, Boolean.class); evaluate("3L < 5L", true, Boolean.class);
...@@ -49,6 +53,15 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -49,6 +53,15 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("5.0d < 3.0d", false, Boolean.class); evaluate("5.0d < 3.0d", false, Boolean.class);
evaluate("'abc' < 'def'",true,Boolean.class); evaluate("'abc' < 'def'",true,Boolean.class);
evaluate("'def' < 'abc'",false,Boolean.class); evaluate("'def' < 'abc'",false,Boolean.class);
evaluate("new java.math.BigDecimal('3') < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') < new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') < 5", true, Boolean.class);
evaluate("3L < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L < new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d < new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("3 lt 5", true, Boolean.class); evaluate("3 lt 5", true, Boolean.class);
evaluate("5 lt 3", false, Boolean.class); evaluate("5 lt 3", false, Boolean.class);
...@@ -58,6 +71,15 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -58,6 +71,15 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("5.0d Lt 3.0d", false, Boolean.class); evaluate("5.0d Lt 3.0d", false, Boolean.class);
evaluate("'abc' LT 'def'",true,Boolean.class); evaluate("'abc' LT 'def'",true,Boolean.class);
evaluate("'def' lt 'abc'",false,Boolean.class); evaluate("'def' lt 'abc'",false,Boolean.class);
evaluate("new java.math.BigDecimal('3') lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') lt new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') lt 5", true, Boolean.class);
evaluate("3L lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L lt new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d lt new java.math.BigDecimal('3.0')", false, Boolean.class);
} }
@Test @Test
...@@ -74,6 +96,16 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -74,6 +96,16 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("'abc' <= 'def'",true,Boolean.class); evaluate("'abc' <= 'def'",true,Boolean.class);
evaluate("'def' <= 'abc'",false,Boolean.class); evaluate("'def' <= 'abc'",false,Boolean.class);
evaluate("'abc' <= 'abc'",true,Boolean.class); evaluate("'abc' <= 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') <= new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') <= 5", true, Boolean.class);
evaluate("3L <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L <= new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d <= new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("3 le 5", true, Boolean.class); evaluate("3 le 5", true, Boolean.class);
evaluate("5 le 3", false, Boolean.class); evaluate("5 le 3", false, Boolean.class);
...@@ -87,6 +119,16 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -87,6 +119,16 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("'abc' Le 'def'",true,Boolean.class); evaluate("'abc' Le 'def'",true,Boolean.class);
evaluate("'def' LE 'abc'",false,Boolean.class); evaluate("'def' LE 'abc'",false,Boolean.class);
evaluate("'abc' le 'abc'",true,Boolean.class); evaluate("'abc' le 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') le new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') le 5", true, Boolean.class);
evaluate("3L le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L le new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d le new java.math.BigDecimal('3.0')", true, Boolean.class);
} }
@Test @Test
...@@ -97,6 +139,16 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -97,6 +139,16 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("3.0f == 5.0f", false, Boolean.class); evaluate("3.0f == 5.0f", false, Boolean.class);
evaluate("3.0f == 3.0f", true, Boolean.class); evaluate("3.0f == 3.0f", true, Boolean.class);
evaluate("'abc' == null", false, Boolean.class); evaluate("'abc' == null", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') == new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') == new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') == new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 == new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') == 5", false, Boolean.class);
evaluate("3L == new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d == new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L == new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d == new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d == new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("3 eq 5", false, Boolean.class); evaluate("3 eq 5", false, Boolean.class);
evaluate("5 eQ 3", false, Boolean.class); evaluate("5 eQ 3", false, Boolean.class);
...@@ -104,6 +156,16 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -104,6 +156,16 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("3.0f eq 5.0f", false, Boolean.class); evaluate("3.0f eq 5.0f", false, Boolean.class);
evaluate("3.0f EQ 3.0f", true, Boolean.class); evaluate("3.0f EQ 3.0f", true, Boolean.class);
evaluate("'abc' EQ null", false, Boolean.class); evaluate("'abc' EQ null", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') eq new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') eq new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') eq new java.math.BigDecimal('3')", false, Boolean.class);
evaluate("3 eq new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') eq 5", false, Boolean.class);
evaluate("3L eq new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d eq new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L eq new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d eq new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d eq new java.math.BigDecimal('3.0')", true, Boolean.class);
} }
@Test @Test
...@@ -113,12 +175,32 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -113,12 +175,32 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("6 != 6", false, Boolean.class); evaluate("6 != 6", false, Boolean.class);
evaluate("3.0f != 5.0f", true, Boolean.class); evaluate("3.0f != 5.0f", true, Boolean.class);
evaluate("3.0f != 3.0f", false, Boolean.class); evaluate("3.0f != 3.0f", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') != new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') != new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') != new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 != new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') != 5", true, Boolean.class);
evaluate("3L != new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d != new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L != new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d != new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d != new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("3 ne 5", true, Boolean.class); evaluate("3 ne 5", true, Boolean.class);
evaluate("5 nE 3", true, Boolean.class); evaluate("5 nE 3", true, Boolean.class);
evaluate("6 Ne 6", false, Boolean.class); evaluate("6 Ne 6", false, Boolean.class);
evaluate("3.0f NE 5.0f", true, Boolean.class); evaluate("3.0f NE 5.0f", true, Boolean.class);
evaluate("3.0f ne 3.0f", false, Boolean.class); evaluate("3.0f ne 3.0f", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') ne new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') ne new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('5') ne new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 ne new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') ne 5", true, Boolean.class);
evaluate("3L ne new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3.0d ne new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("3L ne new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d ne new java.math.BigDecimal('3.1')", true, Boolean.class);
evaluate("3.0d ne new java.math.BigDecimal('3.0')", false, Boolean.class);
} }
@Test @Test
...@@ -135,11 +217,31 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -135,11 +217,31 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("'abc' >= 'def'",false,Boolean.class); evaluate("'abc' >= 'def'",false,Boolean.class);
evaluate("'def' >= 'abc'",true,Boolean.class); evaluate("'def' >= 'abc'",true,Boolean.class);
evaluate("'abc' >= 'abc'",true,Boolean.class); evaluate("'abc' >= 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('5') >= new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') >= new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') >= new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 >= new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') >= 5", false, Boolean.class);
evaluate("3L >= new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d >= new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L >= new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d >= new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d >= new java.math.BigDecimal('3.0')", true, Boolean.class);
evaluate("3 GE 5", false, Boolean.class); evaluate("3 GE 5", false, Boolean.class);
evaluate("5 gE 3", true, Boolean.class); evaluate("5 gE 3", true, Boolean.class);
evaluate("6 Ge 6", true, Boolean.class); evaluate("6 Ge 6", true, Boolean.class);
evaluate("3L ge 5L", false, Boolean.class); evaluate("3L ge 5L", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') ge new java.math.BigDecimal('5')", true, Boolean.class);
evaluate("new java.math.BigDecimal('3') ge new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') ge new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 ge new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') ge 5", false, Boolean.class);
evaluate("3L ge new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d ge new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L ge new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d ge new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d ge new java.math.BigDecimal('3.0')", true, Boolean.class);
} }
@Test @Test
...@@ -152,11 +254,29 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -152,11 +254,29 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("5.0d > 3.0d", true, Boolean.class); evaluate("5.0d > 3.0d", true, Boolean.class);
evaluate("'abc' > 'def'",false,Boolean.class); evaluate("'abc' > 'def'",false,Boolean.class);
evaluate("'def' > 'abc'",true,Boolean.class); evaluate("'def' > 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('3') > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') > new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') > 5", false, Boolean.class);
evaluate("3L > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L > new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d > new java.math.BigDecimal('3.0')", false, Boolean.class);
evaluate("3.0d gt 5.0d", false, Boolean.class); evaluate("3.0d gt 5.0d", false, Boolean.class);
evaluate("5.0d gT 3.0d", true, Boolean.class); evaluate("5.0d gT 3.0d", true, Boolean.class);
evaluate("'abc' Gt 'def'",false,Boolean.class); evaluate("'abc' Gt 'def'",false,Boolean.class);
evaluate("'def' GT 'abc'",true,Boolean.class); evaluate("'def' GT 'abc'",true,Boolean.class);
evaluate("new java.math.BigDecimal('3') gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('5') gt new java.math.BigDecimal('3')", true, Boolean.class);
evaluate("3 gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("new java.math.BigDecimal('3') gt 5", false, Boolean.class);
evaluate("3L gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('5')", false, Boolean.class);
evaluate("3L gt new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('3.1')", false, Boolean.class);
evaluate("3.0d gt new java.math.BigDecimal('3.0')", false, Boolean.class);
} }
@Test @Test
...@@ -169,6 +289,32 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -169,6 +289,32 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("3.0d * 5.0d", 15.0d, Double.class); evaluate("3.0d * 5.0d", 15.0d, Double.class);
} }
@Test
public void testMixedOperandsBigDecimal() {
evaluate("3 * new java.math.BigDecimal('5')", new BigDecimal("15"), BigDecimal.class);
evaluate("3L * new java.math.BigDecimal('5')", new BigDecimal("15"), BigDecimal.class);
evaluate("3.0d * new java.math.BigDecimal('5')", new BigDecimal("15.0"), BigDecimal.class);
evaluate("3 + new java.math.BigDecimal('5')", new BigDecimal("8"), BigDecimal.class);
evaluate("3L + new java.math.BigDecimal('5')", new BigDecimal("8"), BigDecimal.class);
evaluate("3.0d + new java.math.BigDecimal('5')", new BigDecimal("8.0"), BigDecimal.class);
evaluate("3 - new java.math.BigDecimal('5')", new BigDecimal("-2"), BigDecimal.class);
evaluate("3L - new java.math.BigDecimal('5')", new BigDecimal("-2"), BigDecimal.class);
evaluate("3.0d - new java.math.BigDecimal('5')", new BigDecimal("-2.0"), BigDecimal.class);
evaluate("3 / new java.math.BigDecimal('5')", new BigDecimal("1"), BigDecimal.class);
evaluate("3 / new java.math.BigDecimal('5.0')", new BigDecimal("0.6"), BigDecimal.class);
evaluate("3 / new java.math.BigDecimal('5.00')", new BigDecimal("0.60"), BigDecimal.class);
evaluate("3L / new java.math.BigDecimal('5.0')", new BigDecimal("0.6"), BigDecimal.class);
evaluate("3.0d / new java.math.BigDecimal('5.0')", new BigDecimal("0.6"), BigDecimal.class);
evaluate("5 % new java.math.BigDecimal('3')", new BigDecimal("2"), BigDecimal.class);
evaluate("3 % new java.math.BigDecimal('5')", new BigDecimal("3"), BigDecimal.class);
evaluate("3L % new java.math.BigDecimal('5')", new BigDecimal("3"), BigDecimal.class);
evaluate("3.0d % new java.math.BigDecimal('5')", new BigDecimal("3.0"), BigDecimal.class);
}
@Test @Test
public void testMathOperatorAdd02() { public void testMathOperatorAdd02() {
evaluate("'hello' + ' ' + 'world'", "hello world", String.class); evaluate("'hello' + ' ' + 'world'", "hello world", String.class);
...@@ -201,6 +347,7 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -201,6 +347,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("7 + 2", "9", Integer.class); evaluate("7 + 2", "9", Integer.class);
evaluate("3.0f + 5.0f", 8.0f, Float.class); evaluate("3.0f + 5.0f", 8.0f, Float.class);
evaluate("3.0d + 5.0d", 8.0d, Double.class); evaluate("3.0d + 5.0d", 8.0d, Double.class);
evaluate("3 + new java.math.BigDecimal('5')", new BigDecimal("8"), BigDecimal.class);
evaluate("'ab' + 2", "ab2", String.class); evaluate("'ab' + 2", "ab2", String.class);
evaluate("2 + 'a'", "2a", String.class); evaluate("2 + 'a'", "2a", String.class);
...@@ -217,6 +364,7 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -217,6 +364,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("+5d",5d,Double.class); evaluate("+5d",5d,Double.class);
evaluate("+5L",5L,Long.class); evaluate("+5L",5L,Long.class);
evaluate("+5",5,Integer.class); evaluate("+5",5,Integer.class);
evaluate("+new java.math.BigDecimal('5')", new BigDecimal("5"),BigDecimal.class);
evaluateAndCheckError("+'abc'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("+'abc'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
// string concatenation // string concatenation
...@@ -240,6 +388,7 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -240,6 +388,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("-5d",-5d,Double.class); evaluate("-5d",-5d,Double.class);
evaluate("-5L",-5L,Long.class); evaluate("-5L",-5L,Long.class);
evaluate("-5",-5,Integer.class); evaluate("-5",-5,Integer.class);
evaluate("-new java.math.BigDecimal('5')", new BigDecimal("-5"),BigDecimal.class);
evaluateAndCheckError("-'abc'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("-'abc'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
} }
...@@ -249,6 +398,8 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -249,6 +398,8 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("3L%2L",1L,Long.class); evaluate("3L%2L",1L,Long.class);
evaluate("3.0f%2.0f",1f,Float.class); evaluate("3.0f%2.0f",1f,Float.class);
evaluate("5.0d % 3.1d", 1.9d, Double.class); evaluate("5.0d % 3.1d", 1.9d, Double.class);
evaluate("new java.math.BigDecimal('5') % new java.math.BigDecimal('3')", new BigDecimal("2"), BigDecimal.class);
evaluate("new java.math.BigDecimal('5') % 3", new BigDecimal("2"), BigDecimal.class);
evaluateAndCheckError("'abc'%'def'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("'abc'%'def'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
} }
...@@ -258,6 +409,10 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -258,6 +409,10 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("4L/2L",2L,Long.class); evaluate("4L/2L",2L,Long.class);
evaluate("3.0f div 5.0f", 0.6f, Float.class); evaluate("3.0f div 5.0f", 0.6f, Float.class);
evaluate("4L DIV 2L",2L,Long.class); evaluate("4L DIV 2L",2L,Long.class);
evaluate("new java.math.BigDecimal('3') / 5", new BigDecimal("1"), BigDecimal.class);
evaluate("new java.math.BigDecimal('3.0') / 5", new BigDecimal("0.6"), BigDecimal.class);
evaluate("new java.math.BigDecimal('3.00') / 5", new BigDecimal("0.60"), BigDecimal.class);
evaluate("new java.math.BigDecimal('3.00') / new java.math.BigDecimal('5.0000')", new BigDecimal("0.6000"), BigDecimal.class);
evaluateAndCheckError("'abc'/'def'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES); evaluateAndCheckError("'abc'/'def'",SpelMessage.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
} }
...@@ -284,6 +439,18 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -284,6 +439,18 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("6.0d % 3.5d", 2.5d, Double.class); evaluate("6.0d % 3.5d", 2.5d, Double.class);
} }
@Test
public void testBigDecimals() {
evaluate("3 + new java.math.BigDecimal('5')", new BigDecimal("8"), BigDecimal.class);
evaluate("3 - new java.math.BigDecimal('5')", new BigDecimal("-2"), BigDecimal.class);
evaluate("3 * new java.math.BigDecimal('5')", new BigDecimal("15"), BigDecimal.class);
evaluate("3 / new java.math.BigDecimal('5')", new BigDecimal("1"), BigDecimal.class);
evaluate("5 % new java.math.BigDecimal('3')", new BigDecimal("2"), BigDecimal.class);
evaluate("new java.math.BigDecimal('5') % 3", new BigDecimal("2"), BigDecimal.class);
evaluate("new java.math.BigDecimal('5') ^ 3", new BigDecimal("125"), BigDecimal.class);
}
@Test @Test
public void testOperatorNames() throws Exception { public void testOperatorNames() throws Exception {
Operator node = getOperatorNode((SpelExpression)parser.parseExpression("1==3")); Operator node = getOperatorNode((SpelExpression)parser.parseExpression("1==3"));
...@@ -335,6 +502,7 @@ public class OperatorTests extends ExpressionTestCase { ...@@ -335,6 +502,7 @@ public class OperatorTests extends ExpressionTestCase {
evaluate("3.0d^2.0d",9.0d,Double.class); evaluate("3.0d^2.0d",9.0d,Double.class);
evaluate("3L^2L",9L,Long.class); evaluate("3L^2L",9L,Long.class);
evaluate("(2^32)^2",9223372036854775807L,Long.class); evaluate("(2^32)^2",9223372036854775807L,Long.class);
evaluate("new java.math.BigDecimal('5') ^ 3", new BigDecimal("125"), BigDecimal.class);
} }
@Test @Test
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册