SPR-6059 Avoiding NPE for OR operator. If the value is null instead of a valid boolean or Boolean, it will now trigger an EvaluationException.
This commit is contained in:
parent
4a315ba6d1
commit
53eb612a68
|
|
@ -20,12 +20,14 @@ import org.springframework.expression.EvaluationException;
|
||||||
import org.springframework.expression.TypedValue;
|
import org.springframework.expression.TypedValue;
|
||||||
import org.springframework.expression.spel.ExpressionState;
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
import org.springframework.expression.spel.SpelEvaluationException;
|
import org.springframework.expression.spel.SpelEvaluationException;
|
||||||
|
import org.springframework.expression.spel.SpelMessage;
|
||||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the boolean AND operation.
|
* Represents the boolean AND operation.
|
||||||
*
|
*
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
|
* @author Mark Fisher
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class OpAnd extends Operator {
|
public class OpAnd extends Operator {
|
||||||
|
|
@ -40,7 +42,9 @@ public class OpAnd extends Operator {
|
||||||
boolean rightValue;
|
boolean rightValue;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
leftValue = (Boolean)state.convertValue(getLeftOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
TypedValue typedValue = getLeftOperand().getValueInternal(state);
|
||||||
|
this.assertTypedValueNotNull(typedValue);
|
||||||
|
leftValue = (Boolean)state.convertValue(typedValue, BOOLEAN_TYPE_DESCRIPTOR);
|
||||||
}
|
}
|
||||||
catch (SpelEvaluationException ee) {
|
catch (SpelEvaluationException ee) {
|
||||||
ee.setPosition(getLeftOperand().getStartPosition());
|
ee.setPosition(getLeftOperand().getStartPosition());
|
||||||
|
|
@ -52,7 +56,9 @@ public class OpAnd extends Operator {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rightValue = (Boolean)state.convertValue(getRightOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
TypedValue typedValue = getRightOperand().getValueInternal(state);
|
||||||
|
this.assertTypedValueNotNull(typedValue);
|
||||||
|
rightValue = (Boolean)state.convertValue(typedValue, BOOLEAN_TYPE_DESCRIPTOR);
|
||||||
}
|
}
|
||||||
catch (SpelEvaluationException ee) {
|
catch (SpelEvaluationException ee) {
|
||||||
ee.setPosition(getRightOperand().getStartPosition());
|
ee.setPosition(getRightOperand().getStartPosition());
|
||||||
|
|
@ -62,4 +68,10 @@ public class OpAnd extends Operator {
|
||||||
return /* leftValue && */BooleanTypedValue.forValue(rightValue);
|
return /* leftValue && */BooleanTypedValue.forValue(rightValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertTypedValueNotNull(TypedValue typedValue) {
|
||||||
|
if (TypedValue.NULL_TYPED_VALUE.equals(typedValue)) {
|
||||||
|
throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, "null", "boolean");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,14 +17,17 @@
|
||||||
package org.springframework.expression.spel.ast;
|
package org.springframework.expression.spel.ast;
|
||||||
|
|
||||||
import org.springframework.expression.EvaluationException;
|
import org.springframework.expression.EvaluationException;
|
||||||
|
import org.springframework.expression.TypedValue;
|
||||||
import org.springframework.expression.spel.ExpressionState;
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
import org.springframework.expression.spel.SpelEvaluationException;
|
import org.springframework.expression.spel.SpelEvaluationException;
|
||||||
|
import org.springframework.expression.spel.SpelMessage;
|
||||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the boolean OR operation.
|
* Represents the boolean OR operation.
|
||||||
*
|
*
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
|
* @author Mark Fisher
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class OpOr extends Operator {
|
public class OpOr extends Operator {
|
||||||
|
|
@ -37,8 +40,10 @@ public class OpOr extends Operator {
|
||||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||||
boolean leftValue;
|
boolean leftValue;
|
||||||
boolean rightValue;
|
boolean rightValue;
|
||||||
try {
|
try {
|
||||||
leftValue = (Boolean)state.convertValue(getLeftOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
TypedValue typedValue = getLeftOperand().getValueInternal(state);
|
||||||
|
this.assertTypedValueNotNull(typedValue);
|
||||||
|
leftValue = (Boolean)state.convertValue(typedValue, BOOLEAN_TYPE_DESCRIPTOR);
|
||||||
}
|
}
|
||||||
catch (SpelEvaluationException see) {
|
catch (SpelEvaluationException see) {
|
||||||
see.setPosition(getLeftOperand().getStartPosition());
|
see.setPosition(getLeftOperand().getStartPosition());
|
||||||
|
|
@ -50,7 +55,9 @@ public class OpOr extends Operator {
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
rightValue = (Boolean)state.convertValue(getRightOperand().getValueInternal(state), BOOLEAN_TYPE_DESCRIPTOR);
|
TypedValue typedValue = getRightOperand().getValueInternal(state);
|
||||||
|
this.assertTypedValueNotNull(typedValue);
|
||||||
|
rightValue = (Boolean)state.convertValue(typedValue, BOOLEAN_TYPE_DESCRIPTOR);
|
||||||
}
|
}
|
||||||
catch (SpelEvaluationException see) {
|
catch (SpelEvaluationException see) {
|
||||||
see.setPosition(getRightOperand().getStartPosition()); // TODO end positions here and in similar situations
|
see.setPosition(getRightOperand().getStartPosition()); // TODO end positions here and in similar situations
|
||||||
|
|
@ -60,4 +67,10 @@ public class OpOr extends Operator {
|
||||||
return BooleanTypedValue.forValue(leftValue || rightValue);
|
return BooleanTypedValue.forValue(leftValue || rightValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertTypedValueNotNull(TypedValue typedValue) {
|
||||||
|
if (TypedValue.NULL_TYPED_VALUE.equals(typedValue)) {
|
||||||
|
throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, "null", "boolean");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,16 +16,18 @@
|
||||||
|
|
||||||
package org.springframework.expression.spel.ast;
|
package org.springframework.expression.spel.ast;
|
||||||
|
|
||||||
import org.springframework.core.convert.TypeDescriptor;
|
|
||||||
import org.springframework.expression.EvaluationException;
|
import org.springframework.expression.EvaluationException;
|
||||||
|
import org.springframework.expression.TypedValue;
|
||||||
import org.springframework.expression.spel.ExpressionState;
|
import org.springframework.expression.spel.ExpressionState;
|
||||||
import org.springframework.expression.spel.SpelEvaluationException;
|
import org.springframework.expression.spel.SpelEvaluationException;
|
||||||
|
import org.springframework.expression.spel.SpelMessage;
|
||||||
import org.springframework.expression.spel.support.BooleanTypedValue;
|
import org.springframework.expression.spel.support.BooleanTypedValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a NOT operation.
|
* Represents a NOT operation.
|
||||||
*
|
*
|
||||||
* @author Andy Clement
|
* @author Andy Clement
|
||||||
|
* @author Mark Fisher
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so do not extend BinaryOperator
|
public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so do not extend BinaryOperator
|
||||||
|
|
@ -37,7 +39,11 @@ public class OperatorNot extends SpelNodeImpl { // Not is a unary operator so do
|
||||||
@Override
|
@Override
|
||||||
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
public BooleanTypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||||
try {
|
try {
|
||||||
boolean value = (Boolean) state.convertValue(children[0].getValueInternal(state), TypeDescriptor.valueOf(boolean.class));
|
TypedValue typedValue = children[0].getValueInternal(state);
|
||||||
|
if (TypedValue.NULL_TYPED_VALUE.equals(typedValue)) {
|
||||||
|
throw new SpelEvaluationException(SpelMessage.TYPE_CONVERSION_ERROR, "null", "boolean");
|
||||||
|
}
|
||||||
|
boolean value = (Boolean) state.convertValue(typedValue, BOOLEAN_TYPE_DESCRIPTOR);
|
||||||
return BooleanTypedValue.forValue(!value);
|
return BooleanTypedValue.forValue(!value);
|
||||||
}
|
}
|
||||||
catch (SpelEvaluationException see) {
|
catch (SpelEvaluationException see) {
|
||||||
|
|
|
||||||
|
|
@ -308,6 +308,26 @@ public class EvaluationTests extends ExpressionTestCase {
|
||||||
parser.parseExpression("!null").getValue();
|
parser.parseExpression("!null").getValue();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected = EvaluationException.class)
|
||||||
|
public void testAndWithNullValueOnLeft() {
|
||||||
|
parser.parseExpression("null and true").getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = EvaluationException.class)
|
||||||
|
public void testAndWithNullValueOnRight() {
|
||||||
|
parser.parseExpression("true and null").getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = EvaluationException.class)
|
||||||
|
public void testOrWithNullValueOnLeft() {
|
||||||
|
parser.parseExpression("null or false").getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = EvaluationException.class)
|
||||||
|
public void testOrWithNullValueOnRight() {
|
||||||
|
parser.parseExpression("false or null").getValue();
|
||||||
|
}
|
||||||
|
|
||||||
// assignment
|
// assignment
|
||||||
@Test
|
@Test
|
||||||
public void testAssignmentToVariables01() {
|
public void testAssignmentToVariables01() {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue