Skip to content

SPR-9164 - Added BigDecimal capabilities to SpEl numeric operators #80

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -58,7 +60,12 @@ public TypedValue getValueInternal(ExpressionState state) throws EvaluationExcep

if (operandValue instanceof Number) {
Number op1 = (Number) operandValue;
if (op1 instanceof Double) {
if (op1 instanceof BigDecimal) {
BigDecimal bd = (BigDecimal) op1;
newValue = new TypedValue(bd.subtract(BigDecimal.ONE),
operandTypedValue.getTypeDescriptor());
}
else if (op1 instanceof Double) {
newValue = new TypedValue(op1.doubleValue() - 1.0d,
operandTypedValue.getTypeDescriptor());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@

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.
Expand All @@ -42,19 +46,24 @@ public TypedValue getValueInternal(ExpressionState state) throws EvaluationExcep
if (operandOne instanceof Number && operandTwo instanceof Number) {
Number op1 = (Number) operandOne;
Number op2 = (Number) operandTwo;
if (op1 instanceof Double || op2 instanceof Double) {
if (op1 instanceof BigDecimal || op2 instanceof BigDecimal) {
BigDecimal op1BD = NumberUtils.convertNumberToTargetClass(op1, BigDecimal.class);
BigDecimal op2BD = NumberUtils.convertNumberToTargetClass(op2, BigDecimal.class);
int scale = Math.max(op1BD.scale(), op2BD.scale());
return new TypedValue(op1BD.divide(op2BD, scale, RoundingMode.HALF_EVEN));
}
if (op1 instanceof Double || op2 instanceof Double) {
return new TypedValue(op1.doubleValue() / op2.doubleValue());
}
else if (op1 instanceof Float || op2 instanceof Float) {
if (op1 instanceof Float || op2 instanceof Float) {
return new TypedValue(op1.floatValue() / op2.floatValue());
}
else if (op1 instanceof Long || op2 instanceof Long) {
if (op1 instanceof Long || op2 instanceof Long) {
return new TypedValue(op1.longValue() / op2.longValue());
}
else {
// TODO what about non-int result of the division?
return new TypedValue(op1.intValue() / op2.intValue());
}

// TODO what about non-int result of the division?
return new TypedValue(op1.intValue() / op2.intValue());
}
return state.operate(Operation.DIVIDE, operandOne, operandTwo);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@

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.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;

/**
* Implements equality operator.
Expand All @@ -41,18 +46,21 @@ public BooleanTypedValue getValueInternal(ExpressionState state)
if (left instanceof Number && right instanceof Number) {
Number op1 = (Number) left;
Number op2 = (Number) right;
if (op1 instanceof BigDecimal || op2 instanceof BigDecimal) {
BigDecimal bd1 = NumberUtils.convertNumberToTargetClass(op1, BigDecimal.class);
BigDecimal bd2 = NumberUtils.convertNumberToTargetClass(op2, BigDecimal.class);
return BooleanTypedValue.forValue(bd1.compareTo(bd2) == 0);
}
if (op1 instanceof Double || op2 instanceof Double) {
return BooleanTypedValue.forValue(op1.doubleValue() == op2.doubleValue());
}
else if (op1 instanceof Float || op2 instanceof Float) {
if (op1 instanceof Float || op2 instanceof Float) {
return BooleanTypedValue.forValue(op1.floatValue() == op2.floatValue());
}
else if (op1 instanceof Long || op2 instanceof Long) {
if (op1 instanceof Long || op2 instanceof Long) {
return BooleanTypedValue.forValue(op1.longValue() == op2.longValue());
}
else {
return BooleanTypedValue.forValue(op1.intValue() == op2.intValue());
}
return BooleanTypedValue.forValue(op1.intValue() == op2.intValue());
}
if (left != null && (left instanceof Comparable)) {
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,14 @@
*/
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.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;

/**
* Implements greater-than-or-equal operator.
Expand All @@ -39,18 +44,21 @@ public BooleanTypedValue getValueInternal(ExpressionState state) throws Evaluati
if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left;
Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal bdLeft = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal bdRight = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return BooleanTypedValue.forValue(bdLeft.compareTo(bdRight) >= 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@

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.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;

/**
* Implements greater-than operator.
Expand All @@ -40,15 +45,18 @@ public BooleanTypedValue getValueInternal(ExpressionState state) throws Evaluati
if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left;
Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal bdLeft = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal bdRight = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return BooleanTypedValue.forValue(bdLeft.compareTo(bdRight) > 0);
}
if (leftNumber instanceof Double || rightNumber instanceof Double) {
return BooleanTypedValue.forValue(leftNumber.doubleValue() > rightNumber.doubleValue());
}
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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -56,7 +58,12 @@ public TypedValue getValueInternal(ExpressionState state) throws EvaluationExcep

if (operandValue instanceof Number) {
Number op1 = (Number) operandValue;
if (op1 instanceof Double) {
if (op1 instanceof BigDecimal) {
BigDecimal bd = (BigDecimal) op1;
newValue = new TypedValue(bd.add(BigDecimal.ONE),
operandTypedValue.getTypeDescriptor());
}
else if (op1 instanceof Double) {
newValue = new TypedValue(op1.doubleValue() + 1.0d,
operandTypedValue.getTypeDescriptor());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@

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.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;

/**
* Implements the less-than-or-equal operator.
Expand All @@ -41,18 +46,21 @@ public BooleanTypedValue getValueInternal(ExpressionState state)
if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left;
Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal bdLeft = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal bdRight = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return BooleanTypedValue.forValue(bdLeft.compareTo(bdRight) <= 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,14 @@

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.SpelEvaluationException;
import org.springframework.expression.spel.SpelMessage;
import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;

/**
* Implements the less-than operator.
Expand All @@ -42,18 +47,21 @@ public BooleanTypedValue getValueInternal(ExpressionState state)
if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left;
Number rightNumber = (Number) right;
if (leftNumber instanceof BigDecimal || rightNumber instanceof BigDecimal) {
BigDecimal bdLeft = NumberUtils.convertNumberToTargetClass(leftNumber, BigDecimal.class);
BigDecimal bdRight = NumberUtils.convertNumberToTargetClass(rightNumber, BigDecimal.class);
return BooleanTypedValue.forValue(bdLeft.compareTo(bdRight) < 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);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,27 @@

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
* @since 3.0
Expand All @@ -53,6 +57,11 @@ public TypedValue getValueInternal(ExpressionState state) throws EvaluationExcep
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());
}
Expand All @@ -76,18 +85,20 @@ public TypedValue getValueInternal(ExpressionState state) throws EvaluationExcep
if (left instanceof Number && right instanceof Number) {
Number op1 = (Number) left;
Number op2 = (Number) right;
if (op1 instanceof BigDecimal || op2 instanceof BigDecimal) {
BigDecimal bd1 = NumberUtils.convertNumberToTargetClass(op1, BigDecimal.class);
BigDecimal bd2 = NumberUtils.convertNumberToTargetClass(op2, BigDecimal.class);
return new TypedValue(bd1.subtract(bd2));
}
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 (op1 instanceof Long || op2 instanceof Long) {
return new TypedValue(op1.longValue() - op2.longValue());
}

return new TypedValue(op1.intValue() - op2.intValue());
}
else if (left instanceof String && right instanceof Integer
Expand Down
Loading