Merge pull request #406 from aclement/fix-SPR-9194

* fix-SPR-9194:
  Change SpEL equality operators to use .equals
This commit is contained in:
Phillip Webb 2013-11-21 12:08:40 -08:00
commit a41958435a
6 changed files with 69 additions and 52 deletions

View File

@ -28,6 +28,7 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OpEQ extends Operator { public class OpEQ extends Operator {
public OpEQ(int pos, SpelNodeImpl... operands) { public OpEQ(int pos, SpelNodeImpl... operands) {
super("==", pos, operands); super("==", pos, operands);
} }
@ -38,29 +39,7 @@ public class OpEQ extends Operator {
throws EvaluationException { throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue(); Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue(); Object right = getRightOperand().getValueInternal(state).getValue();
if (left instanceof Number && right instanceof Number) { return BooleanTypedValue.forValue(equalityCheck(state, left, right));
Number op1 = (Number) left;
Number op2 = (Number) right;
if (op1 instanceof Double || op2 instanceof Double) {
return BooleanTypedValue.forValue(op1.doubleValue() == op2.doubleValue());
}
else if (op1 instanceof Float || op2 instanceof Float) {
return BooleanTypedValue.forValue(op1.floatValue() == op2.floatValue());
}
else if (op1 instanceof Long || op2 instanceof Long) {
return BooleanTypedValue.forValue(op1.longValue() == op2.longValue());
}
else {
return BooleanTypedValue.forValue(op1.intValue() == op2.intValue());
}
}
if (left != null && (left instanceof Comparable)) {
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left,
right) == 0);
}
else {
return BooleanTypedValue.forValue(left == right);
}
} }
} }

View File

@ -28,6 +28,7 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OpGT extends Operator { public class OpGT extends Operator {
public OpGT(int pos, SpelNodeImpl... operands) { public OpGT(int pos, SpelNodeImpl... operands) {
super(">", pos, operands); super(">", pos, operands);
} }
@ -43,6 +44,9 @@ public class OpGT extends Operator {
if (leftNumber instanceof Double || rightNumber instanceof Double) { if (leftNumber instanceof Double || rightNumber instanceof Double) {
return BooleanTypedValue.forValue(leftNumber.doubleValue() > rightNumber.doubleValue()); return BooleanTypedValue.forValue(leftNumber.doubleValue() > rightNumber.doubleValue());
} }
else if (leftNumber instanceof Float || rightNumber instanceof Float) {
return BooleanTypedValue.forValue(leftNumber.floatValue() > rightNumber.floatValue());
}
else if (leftNumber instanceof Long || rightNumber instanceof Long) { else if (leftNumber instanceof Long || rightNumber instanceof Long) {
return BooleanTypedValue.forValue(leftNumber.longValue() > rightNumber.longValue()); return BooleanTypedValue.forValue(leftNumber.longValue() > rightNumber.longValue());
} }

View File

@ -28,6 +28,7 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OpLT extends Operator { public class OpLT extends Operator {
public OpLT(int pos, SpelNodeImpl... operands) { public OpLT(int pos, SpelNodeImpl... operands) {
super("<", pos, operands); super("<", pos, operands);
} }
@ -38,7 +39,7 @@ public class OpLT extends Operator {
throws EvaluationException { throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue(); Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue(); Object right = getRightOperand().getValueInternal(state).getValue();
// TODO could leave all of these to the comparator - just seems quicker to do some here
if (left instanceof Number && right instanceof Number) { if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left; Number leftNumber = (Number) left;
Number rightNumber = (Number) right; Number rightNumber = (Number) right;

View File

@ -28,6 +28,7 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/ */
public class OpNE extends Operator { public class OpNE extends Operator {
public OpNE(int pos, SpelNodeImpl... operands) { public OpNE(int pos, SpelNodeImpl... operands) {
super("!=", pos, operands); super("!=", pos, operands);
} }
@ -35,35 +36,9 @@ public class OpNE extends Operator {
@Override @Override
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException { public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue(); Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue(); Object right = getRightOperand().getValueInternal(state).getValue();
return BooleanTypedValue.forValue(!equalityCheck(state, left, right));
if (left instanceof Number && right instanceof Number) {
Number op1 = (Number) left;
Number op2 = (Number) right;
if (op1 instanceof Double || op2 instanceof Double) {
return BooleanTypedValue.forValue(op1.doubleValue() != op2.doubleValue());
}
if (op1 instanceof Float || op2 instanceof Float) {
return BooleanTypedValue.forValue(op1.floatValue() != op2.floatValue());
}
if (op1 instanceof Long || op2 instanceof Long) {
return BooleanTypedValue.forValue(op1.longValue() != op2.longValue());
}
return BooleanTypedValue.forValue(op1.intValue() != op2.intValue());
}
if (left != null && (left instanceof Comparable)) {
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left,
right) != 0);
}
return BooleanTypedValue.forValue(left != right);
} }
} }

View File

@ -16,6 +16,8 @@
package org.springframework.expression.spel.ast; package org.springframework.expression.spel.ast;
import org.springframework.expression.spel.ExpressionState;
/** /**
* Common supertype for operators that operate on either one or two operands. In the case * Common supertype for operators that operate on either one or two operands. In the case
* of multiply or divide there would be two operands, but for unary plus or minus, there * of multiply or divide there would be two operands, but for unary plus or minus, there
@ -26,7 +28,7 @@ package org.springframework.expression.spel.ast;
*/ */
public abstract class Operator extends SpelNodeImpl { public abstract class Operator extends SpelNodeImpl {
String operatorName; private final String operatorName;
public Operator(String payload,int pos,SpelNodeImpl... operands) { public Operator(String payload,int pos,SpelNodeImpl... operands) {
@ -63,4 +65,31 @@ public abstract class Operator extends SpelNodeImpl {
return sb.toString(); return sb.toString();
} }
protected boolean equalityCheck(ExpressionState state, Object left, Object right) {
if (left instanceof Number && right instanceof Number) {
Number op1 = (Number) left;
Number op2 = (Number) right;
if (op1 instanceof Double || op2 instanceof Double) {
return (op1.doubleValue() == op2.doubleValue());
}
if (op1 instanceof Float || op2 instanceof Float) {
return (op1.floatValue() == op2.floatValue());
}
if (op1 instanceof Long || op2 instanceof Long) {
return (op1.longValue() == op2.longValue());
}
return (op1.intValue() == op2.intValue());
}
if (left != null && (left instanceof Comparable)) {
return (state.getTypeComparator().compare(left, right) == 0);
}
return (left == null ? right == null : left.equals(right));
}
} }

View File

@ -1839,6 +1839,19 @@ public class SpelReproTests extends ExpressionTestCase {
equalTo((Object) "name")); equalTo((Object) "name"));
} }
@Test
public void testOperatorEq_SPR9194() {
TestClass2 one = new TestClass2("abc");
TestClass2 two = new TestClass2("abc");
Map<String,TestClass2> map = new HashMap<String,TestClass2>();
map.put("one",one);
map.put("two",two);
SpelExpressionParser parser = new SpelExpressionParser();
Expression classNameExpression = parser.parseExpression("['one'] == ['two']");
assertTrue(classNameExpression.getValue(map,Boolean.class));
}
private static enum ABC {A, B, C} private static enum ABC {A, B, C}
@ -1922,4 +1935,20 @@ public class SpelReproTests extends ExpressionTestCase {
} }
} }
static class TestClass2 { // SPR-9194
String string;
public TestClass2(String string) {
this.string = string;
}
public boolean equals(Object o) {
if (o instanceof TestClass2) {
return string.equals(((TestClass2)o).string);
}
return false;
}
}
} }