Skip to content

Commit 87e443b

Browse files
author
Phillip Webb
committed
Merge pull request #80 from giovannidalloglio/SPR-9164
* SPR-9164: Add BigDecimal support for SpEl numeric operations
2 parents a419584 + d0ab131 commit 87e443b

File tree

18 files changed

+569
-160
lines changed

18 files changed

+569
-160
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDec.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.expression.spel.ast;
1818

19+
import java.math.BigDecimal;
20+
1921
import org.springframework.expression.EvaluationException;
2022
import org.springframework.expression.Operation;
2123
import org.springframework.expression.TypedValue;
@@ -29,6 +31,7 @@
2931
* appropriate exceptions if the operand in question does not support decrement.
3032
*
3133
* @author Andy Clement
34+
* @author Giovanni Dall'Oglio Risso
3235
* @since 3.2
3336
*/
3437
public class OpDec extends Operator {
@@ -58,7 +61,11 @@ public TypedValue getValueInternal(ExpressionState state) throws EvaluationExcep
5861

5962
if (operandValue instanceof Number) {
6063
Number op1 = (Number) operandValue;
61-
if (op1 instanceof Double) {
64+
if (op1 instanceof BigDecimal) {
65+
newValue = new TypedValue(((BigDecimal) op1).subtract(BigDecimal.ONE),
66+
operandTypedValue.getTypeDescriptor());
67+
}
68+
else if (op1 instanceof Double) {
6269
newValue = new TypedValue(op1.doubleValue() - 1.0d,
6370
operandTypedValue.getTypeDescriptor());
6471
}
@@ -79,7 +86,7 @@ else if (op1 instanceof Short) {
7986
operandTypedValue.getTypeDescriptor());
8087
}
8188
}
82-
if (newValue==null) {
89+
if (newValue == null) {
8390
try {
8491
newValue = state.operate(Operation.SUBTRACT, returnValue.getValue(), 1);
8592
}

spring-expression/src/main/java/org/springframework/expression/spel/ast/OpDivide.java

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,47 +16,62 @@
1616

1717
package org.springframework.expression.spel.ast;
1818

19+
import java.math.BigDecimal;
20+
import java.math.RoundingMode;
21+
1922
import org.springframework.expression.EvaluationException;
2023
import org.springframework.expression.Operation;
2124
import org.springframework.expression.TypedValue;
2225
import org.springframework.expression.spel.ExpressionState;
26+
import org.springframework.util.NumberUtils;
2327

2428
/**
2529
* Implements division operator.
2630
*
2731
* @author Andy Clement
2832
* @author Juergen Hoeller
33+
* @author Giovanni Dall'Oglio Risso
2934
* @since 3.0
3035
*/
3136
public class OpDivide extends Operator {
3237

38+
3339
public OpDivide(int pos, SpelNodeImpl... operands) {
3440
super("/", pos, operands);
3541
}
3642

3743

3844
@Override
3945
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
40-
Object operandOne = getLeftOperand().getValueInternal(state).getValue();
41-
Object operandTwo = getRightOperand().getValueInternal(state).getValue();
42-
if (operandOne instanceof Number && operandTwo instanceof Number) {
43-
Number op1 = (Number) operandOne;
44-
Number op2 = (Number) operandTwo;
45-
if (op1 instanceof Double || op2 instanceof Double) {
46-
return new TypedValue(op1.doubleValue() / op2.doubleValue());
46+
Object leftOperand = getLeftOperand().getValueInternal(state).getValue();
47+
Object rightOperand = getRightOperand().getValueInternal(state).getValue();
48+
49+
if (leftOperand instanceof Number && rightOperand instanceof Number) {
50+
Number leftNumber = (Number) leftOperand;
51+
Number rightNumber = (Number) rightOperand;
52+
53+
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
54+
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
55+
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
56+
int scale = Math.max(leftBigDecimal.scale(), rightBigDecimal.scale());
57+
return new TypedValue(leftBigDecimal.divide(rightBigDecimal, scale, RoundingMode.HALF_EVEN));
4758
}
48-
else if (op1 instanceof Float || op2 instanceof Float) {
49-
return new TypedValue(op1.floatValue() / op2.floatValue());
59+
60+
if (leftNumber instanceof Double || rightNumber instanceof Double) {
61+
return new TypedValue(leftNumber.doubleValue() / rightNumber.doubleValue());
5062
}
51-
else if (op1 instanceof Long || op2 instanceof Long) {
52-
return new TypedValue(op1.longValue() / op2.longValue());
63+
if (leftNumber instanceof Float || rightNumber instanceof Float) {
64+
return new TypedValue(leftNumber.floatValue() / rightNumber.floatValue());
5365
}
54-
else {
55-
// TODO what about non-int result of the division?
56-
return new TypedValue(op1.intValue() / op2.intValue());
66+
if (leftNumber instanceof Long || rightNumber instanceof Long) {
67+
return new TypedValue(leftNumber.longValue() / rightNumber.longValue());
5768
}
69+
70+
// TODO what about non-int result of the division?
71+
return new TypedValue(leftNumber.intValue() / rightNumber.intValue());
5872
}
59-
return state.operate(Operation.DIVIDE, operandOne, operandTwo);
73+
74+
return state.operate(Operation.DIVIDE, leftOperand, rightOperand);
6075
}
6176

6277
}

spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGE.java

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,23 @@
1515
*/
1616
package org.springframework.expression.spel.ast;
1717

18+
import java.math.BigDecimal;
19+
1820
import org.springframework.expression.EvaluationException;
1921
import org.springframework.expression.spel.ExpressionState;
2022
import org.springframework.expression.spel.support.BooleanTypedValue;
23+
import org.springframework.util.NumberUtils;
2124

2225
/**
2326
* Implements greater-than-or-equal operator.
2427
*
2528
* @author Andy Clement
29+
* @author Giovanni Dall'Oglio Risso
2630
* @since 3.0
2731
*/
2832
public class OpGE extends Operator {
2933

34+
3035
public OpGE(int pos, SpelNodeImpl... operands) {
3136
super(">=", pos, operands);
3237
}
@@ -39,18 +44,25 @@ public BooleanTypedValue getValueInternal(ExpressionState state) throws Evaluati
3944
if (left instanceof Number && right instanceof Number) {
4045
Number leftNumber = (Number) left;
4146
Number rightNumber = (Number) right;
47+
48+
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
49+
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
50+
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
51+
return BooleanTypedValue.forValue(leftBigDecimal.compareTo(rightBigDecimal) >= 0);
52+
}
53+
4254
if (leftNumber instanceof Double || rightNumber instanceof Double) {
4355
return BooleanTypedValue.forValue(leftNumber.doubleValue() >= rightNumber.doubleValue());
4456
}
45-
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
57+
58+
if (leftNumber instanceof Float || rightNumber instanceof Float) {
4659
return BooleanTypedValue.forValue(leftNumber.floatValue() >= rightNumber.floatValue());
4760
}
48-
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
61+
62+
if (leftNumber instanceof Long || rightNumber instanceof Long) {
4963
return BooleanTypedValue.forValue(leftNumber.longValue() >= rightNumber.longValue());
5064
}
51-
else {
52-
return BooleanTypedValue.forValue(leftNumber.intValue() >= rightNumber.intValue());
53-
}
65+
return BooleanTypedValue.forValue(leftNumber.intValue() >= rightNumber.intValue());
5466
}
5567
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) >= 0);
5668
}

spring-expression/src/main/java/org/springframework/expression/spel/ast/OpGT.java

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,18 @@
1616

1717
package org.springframework.expression.spel.ast;
1818

19+
import java.math.BigDecimal;
20+
1921
import org.springframework.expression.EvaluationException;
2022
import org.springframework.expression.spel.ExpressionState;
2123
import org.springframework.expression.spel.support.BooleanTypedValue;
24+
import org.springframework.util.NumberUtils;
2225

2326
/**
2427
* Implements greater-than operator.
2528
*
2629
* @author Andy Clement
30+
* @author Giovanni Dall'Oglio Risso
2731
* @since 3.0
2832
*/
2933
public class OpGT extends Operator {
@@ -38,21 +42,30 @@ public OpGT(int pos, SpelNodeImpl... operands) {
3842
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
3943
Object left = getLeftOperand().getValueInternal(state).getValue();
4044
Object right = getRightOperand().getValueInternal(state).getValue();
45+
4146
if (left instanceof Number && right instanceof Number) {
4247
Number leftNumber = (Number) left;
4348
Number rightNumber = (Number) right;
49+
50+
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
51+
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
52+
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
53+
return BooleanTypedValue.forValue(leftBigDecimal.compareTo(rightBigDecimal) > 0);
54+
}
55+
4456
if (leftNumber instanceof Double || rightNumber instanceof Double) {
4557
return BooleanTypedValue.forValue(leftNumber.doubleValue() > rightNumber.doubleValue());
4658
}
47-
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
59+
60+
if (leftNumber instanceof Float || rightNumber instanceof Float) {
4861
return BooleanTypedValue.forValue(leftNumber.floatValue() > rightNumber.floatValue());
4962
}
50-
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
63+
64+
if (leftNumber instanceof Long || rightNumber instanceof Long) {
5165
return BooleanTypedValue.forValue(leftNumber.longValue() > rightNumber.longValue());
5266
}
53-
else {
54-
return BooleanTypedValue.forValue(leftNumber.intValue() > rightNumber.intValue());
55-
}
67+
68+
return BooleanTypedValue.forValue(leftNumber.intValue() > rightNumber.intValue());
5669
}
5770
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) > 0);
5871
}

spring-expression/src/main/java/org/springframework/expression/spel/ast/OpInc.java

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616

1717
package org.springframework.expression.spel.ast;
1818

19+
import java.math.BigDecimal;
20+
1921
import org.springframework.expression.EvaluationException;
2022
import org.springframework.expression.Operation;
2123
import org.springframework.expression.TypedValue;
@@ -29,6 +31,7 @@
2931
* appropriate exceptions if the operand in question does not support increment.
3032
*
3133
* @author Andy Clement
34+
* @author Giovanni Dall'Oglio Risso
3235
* @since 3.2
3336
*/
3437
public class OpInc extends Operator {
@@ -47,34 +50,38 @@ public OpInc(int pos, boolean postfix, SpelNodeImpl... operands) {
4750
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
4851
SpelNodeImpl operand = getLeftOperand();
4952

50-
ValueRef lvalue = operand.getValueRef(state);
53+
ValueRef valueRef = operand.getValueRef(state);
5154

52-
final TypedValue operandTypedValue = lvalue.getValue();
53-
final Object operandValue = operandTypedValue.getValue();
54-
TypedValue returnValue = operandTypedValue;
55+
final TypedValue typedValue = valueRef.getValue();
56+
final Object value = typedValue.getValue();
57+
TypedValue returnValue = typedValue;
5558
TypedValue newValue = null;
5659

57-
if (operandValue instanceof Number) {
58-
Number op1 = (Number) operandValue;
59-
if (op1 instanceof Double) {
60+
if (value instanceof Number) {
61+
Number op1 = (Number) value;
62+
if (op1 instanceof BigDecimal) {
63+
newValue = new TypedValue(((BigDecimal) op1).add(BigDecimal.ONE),
64+
typedValue.getTypeDescriptor());
65+
}
66+
else if (op1 instanceof Double) {
6067
newValue = new TypedValue(op1.doubleValue() + 1.0d,
61-
operandTypedValue.getTypeDescriptor());
68+
typedValue.getTypeDescriptor());
6269
}
6370
else if (op1 instanceof Float) {
6471
newValue = new TypedValue(op1.floatValue() + 1.0f,
65-
operandTypedValue.getTypeDescriptor());
72+
typedValue.getTypeDescriptor());
6673
}
6774
else if (op1 instanceof Long) {
6875
newValue = new TypedValue(op1.longValue() + 1L,
69-
operandTypedValue.getTypeDescriptor());
76+
typedValue.getTypeDescriptor());
7077
}
7178
else if (op1 instanceof Short) {
7279
newValue = new TypedValue(op1.shortValue() + (short) 1,
73-
operandTypedValue.getTypeDescriptor());
80+
typedValue.getTypeDescriptor());
7481
}
7582
else {
7683
newValue = new TypedValue(op1.intValue() + 1,
77-
operandTypedValue.getTypeDescriptor());
84+
typedValue.getTypeDescriptor());
7885
}
7986
}
8087
if (newValue == null) {
@@ -93,7 +100,7 @@ else if (op1 instanceof Short) {
93100

94101
// set the name value
95102
try {
96-
lvalue.setValue(newValue.getValue());
103+
valueRef.setValue(newValue.getValue());
97104
}
98105
catch (SpelEvaluationException see) {
99106
// if unable to set the value the operand is not writable (e.g. 1++ )

spring-expression/src/main/java/org/springframework/expression/spel/ast/OpLE.java

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,18 +16,23 @@
1616

1717
package org.springframework.expression.spel.ast;
1818

19+
import java.math.BigDecimal;
20+
1921
import org.springframework.expression.EvaluationException;
2022
import org.springframework.expression.spel.ExpressionState;
2123
import org.springframework.expression.spel.support.BooleanTypedValue;
24+
import org.springframework.util.NumberUtils;
2225

2326
/**
2427
* Implements the less-than-or-equal operator.
2528
*
2629
* @author Andy Clement
30+
* @author Giovanni Dall'Oglio Risso
2731
* @since 3.0
2832
*/
2933
public class OpLE extends Operator {
3034

35+
3136
public OpLE(int pos, SpelNodeImpl... operands) {
3237
super("<=", pos, operands);
3338
}
@@ -41,19 +46,28 @@ public BooleanTypedValue getValueInternal(ExpressionState state)
4146
if (left instanceof Number && right instanceof Number) {
4247
Number leftNumber = (Number) left;
4348
Number rightNumber = (Number) right;
49+
50+
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
51+
BigDecimal leftBigDecimal = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
52+
BigDecimal rightBigDecimal = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
53+
return BooleanTypedValue.forValue(leftBigDecimal.compareTo(rightBigDecimal) <= 0);
54+
}
55+
4456
if (leftNumber instanceof Double || rightNumber instanceof Double) {
4557
return BooleanTypedValue.forValue(leftNumber.doubleValue() <= rightNumber.doubleValue());
4658
}
47-
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
59+
60+
if (leftNumber instanceof Float || rightNumber instanceof Float) {
4861
return BooleanTypedValue.forValue(leftNumber.floatValue() <= rightNumber.floatValue());
4962
}
50-
else if (leftNumber instanceof Long || rightNumber instanceof Long) {
63+
64+
if (leftNumber instanceof Long || rightNumber instanceof Long) {
5165
return BooleanTypedValue.forValue(leftNumber.longValue() <= rightNumber.longValue());
5266
}
53-
else {
54-
return BooleanTypedValue.forValue(leftNumber.intValue() <= rightNumber.intValue());
55-
}
67+
68+
return BooleanTypedValue.forValue(leftNumber.intValue() <= rightNumber.intValue());
5669
}
70+
5771
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) <= 0);
5872
}
5973

0 commit comments

Comments
 (0)