EQ/NE do not fail in case of a Comparable mismatch and apply a specific CharSequence equality check

Issue: SPR-11708
This commit is contained in:
Juergen Hoeller
2014-04-21 23:29:40 +02:00
parent 566e0fb317
commit 66bae99d86
6 changed files with 256 additions and 178 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -21,22 +21,19 @@ import org.springframework.expression.spel.ExpressionState;
import org.springframework.expression.spel.support.BooleanTypedValue;
/**
* Implements equality operator.
* Implements the equality operator.
*
* @author Andy Clement
* @since 3.0
*/
public class OpEQ extends Operator {
public OpEQ(int pos, SpelNodeImpl... operands) {
super("==", pos, operands);
}
@Override
public BooleanTypedValue getValueInternal(ExpressionState state)
throws EvaluationException {
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue();
return BooleanTypedValue.forValue(equalityCheck(state, left, right));

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -24,20 +24,19 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
import org.springframework.util.NumberUtils;
/**
* Implements greater-than operator.
* Implements the greater-than operator.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
* @since 3.0
*/
public class OpGT extends Operator {
public OpGT(int pos, SpelNodeImpl... operands) {
super(">", pos, operands);
}
@Override
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
@@ -67,6 +66,12 @@ public class OpGT extends Operator {
return BooleanTypedValue.forValue(leftNumber.intValue() > rightNumber.intValue());
}
if (left instanceof CharSequence && right instanceof CharSequence) {
left = left.toString();
right = right.toString();
}
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) > 0);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -27,20 +27,18 @@ import org.springframework.util.NumberUtils;
* Implements the less-than operator.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
* @since 3.0
*/
public class OpLT extends Operator {
public OpLT(int pos, SpelNodeImpl... operands) {
super("<", pos, operands);
}
@Override
public BooleanTypedValue getValueInternal(ExpressionState state)
throws EvaluationException {
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();
Object right = getRightOperand().getValueInternal(state).getValue();
@@ -68,6 +66,12 @@ public class OpLT extends Operator {
return BooleanTypedValue.forValue(leftNumber.intValue() < rightNumber.intValue());
}
if (left instanceof CharSequence && right instanceof CharSequence) {
left = left.toString();
right = right.toString();
}
return BooleanTypedValue.forValue(state.getTypeComparator().compare(left, right) < 0);
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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,12 +28,10 @@ import org.springframework.expression.spel.support.BooleanTypedValue;
*/
public class OpNE extends Operator {
public OpNE(int pos, SpelNodeImpl... operands) {
super("!=", pos, operands);
}
@Override
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
Object left = getLeftOperand().getValueInternal(state).getValue();

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2013 the original author or authors.
* Copyright 2002-2014 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.
@@ -19,15 +19,17 @@ package org.springframework.expression.spel.ast;
import java.math.BigDecimal;
import org.springframework.expression.spel.ExpressionState;
import org.springframework.util.ClassUtils;
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
* of multiply or divide there would be two operands, but for unary plus or minus, there
* is only one.
* 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 is only one.
*
* @author Andy Clement
* @author Juergen Hoeller
* @author Giovanni Dall'Oglio Risso
* @since 3.0
*/
@@ -70,6 +72,7 @@ public abstract class Operator extends SpelNodeImpl {
return sb.toString();
}
protected boolean equalityCheck(ExpressionState state, Object left, Object right) {
if (left instanceof Number && right instanceof Number) {
Number leftNumber = (Number) left;
@@ -96,11 +99,22 @@ public abstract class Operator extends SpelNodeImpl {
return (leftNumber.intValue() == rightNumber.intValue());
}
if (left != null && (left instanceof Comparable)) {
return (state.getTypeComparator().compare(left, right) == 0);
if (left instanceof CharSequence && right instanceof CharSequence) {
return left.toString().equals(right.toString());
}
return ObjectUtils.nullSafeEquals(left, right);
if (ObjectUtils.nullSafeEquals(left, right)) {
return true;
}
if (left instanceof Comparable && right instanceof Comparable) {
Class<?> ancestor = ClassUtils.determineCommonAncestor(left.getClass(), right.getClass());
if (ancestor != null && Comparable.class.isAssignableFrom(ancestor)) {
return (state.getTypeComparator().compare(left, right) == 0);
}
}
return false;
}
}