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