More tests, corrections in standard comparator, more helper methods in StandardEvaluationContext.
This commit is contained in:
parent
ba613f2e35
commit
46c5340f57
|
|
@ -24,6 +24,6 @@ package org.springframework.expression;
|
|||
*/
|
||||
public enum Operation {
|
||||
|
||||
ADD, SUBTRACT, DIVIDE, MULTIPLY, MODULUS
|
||||
ADD, SUBTRACT, DIVIDE, MULTIPLY, MODULUS, POWER
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import org.springframework.expression.EvaluationContext;
|
|||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.common.ExpressionUtils;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
/**
|
||||
* A SpelExpressions represents a parsed (valid) expression that is ready to be evaluated in a specified context. An
|
||||
|
|
@ -54,7 +55,8 @@ public class SpelExpression implements Expression {
|
|||
* {@inheritDoc}
|
||||
*/
|
||||
public Object getValue() throws EvaluationException {
|
||||
return this.ast.getValue(null);
|
||||
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
|
||||
return this.ast.getValue(expressionState);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -134,11 +136,10 @@ public class SpelExpression implements Expression {
|
|||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getValue(Class<T> expectedResultType) throws EvaluationException {
|
||||
Object result = getValue();
|
||||
// TODO propagate generic-ness into convert
|
||||
return (T) ExpressionUtils.convert(null, result, expectedResultType);
|
||||
ExpressionState expressionState = new ExpressionState(new StandardEvaluationContext());
|
||||
Object result = this.ast.getValue(expressionState);
|
||||
return ExpressionUtils.convert(expressionState.getEvaluationContext(), result, expectedResultType);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* Copyright 2002-2009 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.expression.spel.ast;
|
||||
|
||||
import org.antlr.runtime.Token;
|
||||
import org.springframework.expression.EvaluationException;
|
||||
import org.springframework.expression.Operation;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.spel.ExpressionState;
|
||||
|
||||
/**
|
||||
* The power operator.
|
||||
*
|
||||
* @author Andy Clement
|
||||
* @since 3.0
|
||||
*/
|
||||
public class OperatorPower extends Operator {
|
||||
|
||||
public OperatorPower(Token payload) {
|
||||
super(payload);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypedValue getValueInternal(ExpressionState state) throws EvaluationException {
|
||||
SpelNodeImpl leftOp = getLeftOperand();
|
||||
SpelNodeImpl rightOp = getRightOperand();
|
||||
|
||||
Object operandOne = leftOp.getValueInternal(state).getValue();
|
||||
Object operandTwo = rightOp.getValueInternal(state).getValue();
|
||||
if (operandOne instanceof Number && operandTwo instanceof Number) {
|
||||
Number op1 = (Number) operandOne;
|
||||
Number op2 = (Number) operandTwo;
|
||||
if (op1 instanceof Double || op2 instanceof Double) {
|
||||
return new TypedValue(Math.pow(op1.doubleValue(),op2.doubleValue()),DOUBLE_TYPE_DESCRIPTOR);
|
||||
} else if (op1 instanceof Long || op2 instanceof Long) {
|
||||
double d= Math.pow(op1.longValue(), op2.longValue());
|
||||
return new TypedValue((long)d, LONG_TYPE_DESCRIPTOR);
|
||||
} else {
|
||||
double d= Math.pow(op1.longValue(), op2.longValue());
|
||||
if (d > Integer.MAX_VALUE) {
|
||||
return new TypedValue((long)d,LONG_TYPE_DESCRIPTOR);
|
||||
} else {
|
||||
return new TypedValue((int)d,INTEGER_TYPE_DESCRIPTOR);
|
||||
}
|
||||
}
|
||||
}
|
||||
return state.operate(Operation.POWER, operandOne, operandTwo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOperatorName() {
|
||||
return "^";
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -72,6 +72,9 @@ public class SpelTreeAdaptor extends CommonTreeAdaptor {
|
|||
return new OperatorDivide(payload);
|
||||
case SpringExpressionsLexer.MOD:
|
||||
return new OperatorModulus(payload);
|
||||
case SpringExpressionsLexer.POWER:
|
||||
return new OperatorPower(payload);
|
||||
|
||||
|
||||
case SpringExpressionsLexer.STRING_LITERAL:
|
||||
case SpringExpressionsLexer.DQ_STRING_LITERAL:
|
||||
|
|
|
|||
|
|
@ -68,6 +68,11 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
this.constructorResolvers.add(new ReflectiveConstructorResolver());
|
||||
this.propertyAccessors.add(new ReflectivePropertyResolver());
|
||||
}
|
||||
|
||||
public StandardEvaluationContext(Object rootObject) {
|
||||
this();
|
||||
setRootObject(rootObject);
|
||||
}
|
||||
|
||||
public void setRootObject(Object rootObject) {
|
||||
this.rootObject = new TypedValue(rootObject,TypeDescriptor.forObject(rootObject));
|
||||
|
|
@ -84,6 +89,10 @@ public class StandardEvaluationContext implements EvaluationContext {
|
|||
public void setVariable(String name, Object value) {
|
||||
this.variables.put(name, value);
|
||||
}
|
||||
|
||||
public void setVariables(Map<String,Object> variables) {
|
||||
this.variables.putAll(variables);
|
||||
}
|
||||
|
||||
public void registerFunction(String name, Method method) {
|
||||
this.variables.put(name, method);
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@ package org.springframework.expression.spel.support;
|
|||
|
||||
import org.springframework.expression.TypeComparator;
|
||||
import org.springframework.expression.spel.SpelException;
|
||||
import org.springframework.expression.spel.SpelMessages;
|
||||
|
||||
/**
|
||||
* A simple basic TypeComparator implementation. It supports comparison of numbers and types implementing Comparable.
|
||||
|
|
@ -64,12 +63,15 @@ public class StandardTypeComparator implements TypeComparator {
|
|||
}
|
||||
}
|
||||
|
||||
if (left.getClass() == right.getClass() && left instanceof Comparable) {
|
||||
return ((Comparable) left).compareTo(right);
|
||||
}
|
||||
else {
|
||||
throw new SpelException(SpelMessages.NOT_COMPARABLE, left.getClass(), right.getClass());
|
||||
boolean sameType = left.getClass() == right.getClass();
|
||||
|
||||
if (sameType) {
|
||||
if (left instanceof Comparable) {
|
||||
return ((Comparable) left).compareTo(right);
|
||||
}
|
||||
}
|
||||
// TODO coerce one to be like the other?
|
||||
return left==right?0:1; // identity comparison
|
||||
}
|
||||
|
||||
public boolean canCompare(Object left, Object right) {
|
||||
|
|
|
|||
|
|
@ -40,8 +40,8 @@ public class StandardTypeConverter implements TypeConverter {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T convertValue(Object value, Class<T> targetType) throws EvaluationException {
|
||||
// For activation when conversion service available - this replaces the rest of the method (probably...)
|
||||
// return (T)convertValue(value,TypeDescriptor.valueOf(targetType));
|
||||
// For activation when conversion service available - this replaces the rest of the method (probably...)
|
||||
// return (T)convertValue(value,TypeDescriptor.valueOf(targetType));
|
||||
if (ClassUtils.isAssignableValue(targetType, value)) {
|
||||
return (T) value;
|
||||
}
|
||||
|
|
@ -89,7 +89,7 @@ public class StandardTypeConverter implements TypeConverter {
|
|||
public Object convertValue(Object value, TypeDescriptor typeDescriptor) throws EvaluationException {
|
||||
// For activation when conversion service available - this replaces the rest of the method (probably...)
|
||||
// try {
|
||||
// return (T)conversionService.executeConversion(value, typeDescriptor);
|
||||
// return conversionService.executeConversion(value, typeDescriptor);
|
||||
// } catch (ConversionExecutorNotFoundException cenfe) {
|
||||
// throw new SpelException(cenfe, SpelMessages.TYPE_CONVERSION_ERROR, value.getClass(), typeDescriptor.asString());
|
||||
// } catch (ConversionException ce) {
|
||||
|
|
@ -100,7 +100,7 @@ public class StandardTypeConverter implements TypeConverter {
|
|||
|
||||
public boolean canConvert(Class<?> sourceType, Class<?> targetType) {
|
||||
// For activation when conversion service available - this replaces the rest of the method (probably...)
|
||||
// return canConvert(sourceType,TypeDescriptor.valueOf(targetType));
|
||||
// return canConvert(sourceType,TypeDescriptor.valueOf(targetType));
|
||||
if (ClassUtils.isAssignable(targetType, sourceType) || String.class.equals(targetType)) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,21 +68,6 @@ public class DefaultComparatorUnitTests extends TestCase {
|
|||
assertTrue(comparator.compare("a","a")==0);
|
||||
assertTrue(comparator.compare("a","b")<0);
|
||||
assertTrue(comparator.compare("b","a")>0);
|
||||
|
||||
try {
|
||||
comparator.compare("a",3);
|
||||
fail("Should have failed");
|
||||
} catch (EvaluationException ee) {
|
||||
SpelException sEx = (SpelException)ee;
|
||||
assertEquals(SpelMessages.NOT_COMPARABLE,sEx.getMessageUnformatted());
|
||||
}
|
||||
try {
|
||||
comparator.compare(2,"b");
|
||||
fail("Should have failed");
|
||||
} catch (EvaluationException ee) {
|
||||
SpelException sEx = (SpelException)ee;
|
||||
assertEquals(SpelMessages.NOT_COMPARABLE,sEx.getMessageUnformatted());
|
||||
}
|
||||
}
|
||||
|
||||
public void testCanCompare() throws EvaluationException {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import org.springframework.expression.EvaluationContext;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
|
|
@ -237,5 +238,25 @@ public class EvaluationTests extends ExpressionTestCase {
|
|||
evaluateAndAskForReturnType("3*4+5", (short) 17, Short.class);
|
||||
evaluateAndAskForReturnType("3*4+5", "17", String.class);
|
||||
}
|
||||
|
||||
|
||||
public void testAdvancedNumerics() throws Exception {
|
||||
int twentyFour = parser.parseExpression("2.0 * 3e0 * 4").getValue(Integer.class);
|
||||
assertEquals(24,twentyFour);
|
||||
double one = parser.parseExpression("8.0 / 5e0 % 2").getValue(Double.class);
|
||||
assertEquals(1.6d,one);
|
||||
int o = parser.parseExpression("8.0 / 5e0 % 2").getValue(Integer.class);
|
||||
assertEquals(1,o);
|
||||
int sixteen = parser.parseExpression("-2 ^ 4").getValue(Integer.class);
|
||||
assertEquals(16,sixteen);
|
||||
int minusFortyFive = parser.parseExpression("1+2-3*8^2/2/2").getValue(Integer.class);
|
||||
assertEquals(-45,minusFortyFive);
|
||||
}
|
||||
|
||||
public void testComparison() throws Exception {
|
||||
EvaluationContext context = TestScenarioCreator.getTestEvaluationContext();
|
||||
boolean trueValue = parser.parseExpression("T(java.util.Date) == Birthdate.Class").getValue(context, Boolean.class);
|
||||
assertTrue(trueValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -236,10 +236,21 @@ public class OperatorTests extends ExpressionTestCase {
|
|||
|
||||
node = getOperatorNode((SpelExpression)parser.parseExpression("3 between 4"));
|
||||
assertEquals("between",node.getOperatorName());
|
||||
|
||||
node = getOperatorNode((SpelExpression)parser.parseExpression("3 ^ 4"));
|
||||
assertEquals("^",node.getOperatorName());
|
||||
}
|
||||
|
||||
public void testOperatorOverloading() {
|
||||
evaluateAndCheckError("'a' * '2'", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
evaluateAndCheckError("'a' ^ '2'", SpelMessages.OPERATOR_NOT_SUPPORTED_BETWEEN_TYPES);
|
||||
}
|
||||
|
||||
public void testPower() {
|
||||
evaluate("3^2",9,Integer.class);
|
||||
evaluate("3.0d^2.0d",9.0d,Double.class);
|
||||
evaluate("3L^2L",9L,Long.class);
|
||||
evaluate("(2^32)^2",9223372036854775807L,Long.class);
|
||||
}
|
||||
|
||||
public void testMixedOperands_FloatsAndDoubles() {
|
||||
|
|
|
|||
Loading…
Reference in New Issue