Polishing
Issue: SPR-12803
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@@ -29,6 +26,8 @@ import org.springframework.expression.ParseException;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Common superclass for expression tests.
|
||||
*
|
||||
@@ -36,187 +35,146 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
*/
|
||||
public abstract class ExpressionTestCase {
|
||||
|
||||
private final static boolean DEBUG = false;
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
protected static final boolean SHOULD_BE_WRITABLE = true;
|
||||
|
||||
protected static final boolean SHOULD_NOT_BE_WRITABLE = false;
|
||||
|
||||
protected final static boolean SHOULD_BE_WRITABLE = true;
|
||||
protected final static boolean SHOULD_NOT_BE_WRITABLE = false;
|
||||
|
||||
protected final ExpressionParser parser = new SpelExpressionParser();
|
||||
|
||||
protected final StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
|
||||
|
||||
|
||||
/**
|
||||
* Evaluate an expression and check that the actual result matches the expectedValue and the class of the result
|
||||
* matches the expectedClassOfResult.
|
||||
* @param expression The expression to evaluate
|
||||
* Evaluate an expression and check that the actual result matches the
|
||||
* expectedValue and the class of the result matches the expectedClassOfResult.
|
||||
* @param expression the expression to evaluate
|
||||
* @param expectedValue the expected result for evaluating the expression
|
||||
* @param expectedResultType the expected class of the evaluation result
|
||||
*/
|
||||
public void evaluate(String expression, Object expectedValue, Class<?> expectedResultType) {
|
||||
try {
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
if (expr == null) {
|
||||
fail("Parser returned null for expression");
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
if (expr == null) {
|
||||
fail("Parser returned null for expression");
|
||||
}
|
||||
if (DEBUG) {
|
||||
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
|
||||
}
|
||||
|
||||
Object value = expr.getValue(eContext);
|
||||
|
||||
// Check the return value
|
||||
if (value == null) {
|
||||
if (expectedValue == null) {
|
||||
return; // no point doing other checks
|
||||
}
|
||||
if (DEBUG) {
|
||||
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
|
||||
}
|
||||
// Class<?> expressionType = expr.getValueType();
|
||||
// assertEquals("Type of the expression is not as expected. Should be '"+expectedResultType+"' but is
|
||||
// '"+expressionType+"'",
|
||||
// expectedResultType,expressionType);
|
||||
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, null);
|
||||
}
|
||||
|
||||
Object value = expr.getValue(eContext);
|
||||
Class<?> resultType = value.getClass();
|
||||
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType +
|
||||
"' but result was of type '" + resultType + "'", expectedResultType, resultType);
|
||||
|
||||
// Check the return value
|
||||
if (value == null) {
|
||||
if (expectedValue == null) {
|
||||
return; // no point doing other checks
|
||||
}
|
||||
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
|
||||
null);
|
||||
}
|
||||
|
||||
Class<?> resultType = value.getClass();
|
||||
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType
|
||||
+ "' but result was of type '" + resultType + "'", expectedResultType, resultType);
|
||||
// .equals/* isAssignableFrom */(resultType), truers);
|
||||
|
||||
// TODO isAssignableFrom would allow some room for compatibility
|
||||
// in the above expression...
|
||||
|
||||
if (expectedValue instanceof String) {
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
|
||||
ExpressionTestCase.stringValueOf(value));
|
||||
} else {
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
|
||||
}
|
||||
} catch (EvaluationException ee) {
|
||||
ee.printStackTrace();
|
||||
fail("Unexpected Exception: " + ee.getMessage());
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
fail("Unexpected Exception: " + pe.getMessage());
|
||||
if (expectedValue instanceof String) {
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
|
||||
ExpressionTestCase.stringValueOf(value));
|
||||
}
|
||||
else {
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
|
||||
}
|
||||
}
|
||||
|
||||
public void evaluateAndAskForReturnType(String expression, Object expectedValue, Class<?> expectedResultType) {
|
||||
try {
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
if (expr == null) {
|
||||
fail("Parser returned null for expression");
|
||||
}
|
||||
if (DEBUG) {
|
||||
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
|
||||
}
|
||||
// Class<?> expressionType = expr.getValueType();
|
||||
// assertEquals("Type of the expression is not as expected. Should be '"+expectedResultType+"' but is
|
||||
// '"+expressionType+"'",
|
||||
// expectedResultType,expressionType);
|
||||
|
||||
Object value = expr.getValue(eContext, expectedResultType);
|
||||
if (value == null) {
|
||||
if (expectedValue == null)
|
||||
return; // no point doing other checks
|
||||
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
|
||||
null);
|
||||
}
|
||||
|
||||
Class<?> resultType = value.getClass();
|
||||
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType
|
||||
+ "' but result was of type '" + resultType + "'", expectedResultType, resultType);
|
||||
// .equals/* isAssignableFrom */(resultType), truers);
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
|
||||
// isAssignableFrom would allow some room for compatibility
|
||||
// in the above expression...
|
||||
} catch (EvaluationException ee) {
|
||||
SpelEvaluationException ex = (SpelEvaluationException) ee;
|
||||
ex.printStackTrace();
|
||||
fail("Unexpected EvaluationException: " + ex.getMessage());
|
||||
} catch (ParseException pe) {
|
||||
fail("Unexpected ParseException: " + pe.getMessage());
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
if (expr == null) {
|
||||
fail("Parser returned null for expression");
|
||||
}
|
||||
if (DEBUG) {
|
||||
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
|
||||
}
|
||||
|
||||
Object value = expr.getValue(eContext, expectedResultType);
|
||||
if (value == null) {
|
||||
if (expectedValue == null) {
|
||||
return; // no point doing other checks
|
||||
}
|
||||
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, null);
|
||||
}
|
||||
|
||||
Class<?> resultType = value.getClass();
|
||||
assertEquals("Type of the actual result was not as expected. Expected '" + expectedResultType +
|
||||
"' but result was of type '" + resultType + "'", expectedResultType, resultType);
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate an expression and check that the actual result matches the expectedValue and the class of the result
|
||||
* matches the expectedClassOfResult. This method can also check if the expression is writable (for example, it is a
|
||||
* variable or property reference).
|
||||
*
|
||||
* @param expression The expression to evaluate
|
||||
* Evaluate an expression and check that the actual result matches the
|
||||
* expectedValue and the class of the result matches the expectedClassOfResult.
|
||||
* This method can also check if the expression is writable (for example,
|
||||
* it is a variable or property reference).
|
||||
* @param expression the expression to evaluate
|
||||
* @param expectedValue the expected result for evaluating the expression
|
||||
* @param expectedClassOfResult the expected class of the evaluation result
|
||||
* @param shouldBeWritable should the parsed expression be writable?
|
||||
*/
|
||||
public void evaluate(String expression, Object expectedValue, Class<?> expectedClassOfResult,
|
||||
boolean shouldBeWritable) {
|
||||
try {
|
||||
Expression e = parser.parseExpression(expression);
|
||||
if (e == null) {
|
||||
fail("Parser returned null for expression");
|
||||
public void evaluate(String expression, Object expectedValue, Class<?> expectedClassOfResult, boolean shouldBeWritable) {
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
if (expr == null) {
|
||||
fail("Parser returned null for expression");
|
||||
}
|
||||
if (DEBUG) {
|
||||
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
|
||||
}
|
||||
Object value = expr.getValue(eContext);
|
||||
if (value == null) {
|
||||
if (expectedValue == null) {
|
||||
return; // no point doing other checks
|
||||
}
|
||||
if (DEBUG) {
|
||||
SpelUtilities.printAbstractSyntaxTree(System.out, e);
|
||||
}
|
||||
Object value = e.getValue(eContext);
|
||||
if (value == null) {
|
||||
if (expectedValue == null)
|
||||
return; // no point doing other
|
||||
// checks
|
||||
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue,
|
||||
null);
|
||||
}
|
||||
Class<? extends Object> resultType = value.getClass();
|
||||
if (expectedValue instanceof String) {
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
|
||||
ExpressionTestCase.stringValueOf(value));
|
||||
} else {
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
|
||||
}
|
||||
// assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
|
||||
// ExpressionTestCase.stringValueOf(value));
|
||||
assertEquals("Type of the result was not as expected. Expected '" + expectedClassOfResult
|
||||
+ "' but result was of type '" + resultType + "'", expectedClassOfResult
|
||||
.equals/* isAssignableFrom */(resultType), true);
|
||||
// TODO isAssignableFrom would allow some room for compatibility
|
||||
// in the above expression...
|
||||
assertEquals("Expression returned null value, but expected '" + expectedValue + "'", expectedValue, null);
|
||||
}
|
||||
Class<? extends Object> resultType = value.getClass();
|
||||
if (expectedValue instanceof String) {
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue,
|
||||
ExpressionTestCase.stringValueOf(value));
|
||||
}
|
||||
else {
|
||||
assertEquals("Did not get expected value for expression '" + expression + "'.", expectedValue, value);
|
||||
}
|
||||
assertEquals("Type of the result was not as expected. Expected '" + expectedClassOfResult +
|
||||
"' but result was of type '" + resultType + "'", expectedClassOfResult.equals(resultType), true);
|
||||
|
||||
boolean isWritable = e.isWritable(eContext);
|
||||
if (isWritable != shouldBeWritable) {
|
||||
if (shouldBeWritable)
|
||||
fail("Expected the expression to be writable but it is not");
|
||||
else
|
||||
fail("Expected the expression to be readonly but it is not");
|
||||
}
|
||||
} catch (EvaluationException ee) {
|
||||
ee.printStackTrace();
|
||||
fail("Unexpected Exception: " + ee.getMessage());
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
fail("Unexpected Exception: " + pe.getMessage());
|
||||
boolean isWritable = expr.isWritable(eContext);
|
||||
if (isWritable != shouldBeWritable) {
|
||||
if (shouldBeWritable)
|
||||
fail("Expected the expression to be writable but it is not");
|
||||
else
|
||||
fail("Expected the expression to be readonly but it is not");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the specified expression and ensure the expected message comes out. The message may have inserts and
|
||||
* they will be checked if otherProperties is specified. The first entry in otherProperties should always be the
|
||||
* position.
|
||||
* @param expression The expression to evaluate
|
||||
* @param expectedMessage The expected message
|
||||
* @param otherProperties The expected inserts within the message
|
||||
* Evaluate the specified expression and ensure the expected message comes out.
|
||||
* The message may have inserts and they will be checked if otherProperties is specified.
|
||||
* The first entry in otherProperties should always be the position.
|
||||
* @param expression the expression to evaluate
|
||||
* @param expectedMessage the expected message
|
||||
* @param otherProperties the expected inserts within the message
|
||||
*/
|
||||
protected void evaluateAndCheckError(String expression, SpelMessage expectedMessage, Object... otherProperties) {
|
||||
evaluateAndCheckError(expression, null, expectedMessage, otherProperties);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate the specified expression and ensure the expected message comes out. The message may have inserts and
|
||||
* they will be checked if otherProperties is specified. The first entry in otherProperties should always be the
|
||||
* position.
|
||||
* @param expression The expression to evaluate
|
||||
* @param expectedReturnType Ask the expression return value to be of this type if possible (null indicates don't
|
||||
* ask for conversion)
|
||||
* @param expectedMessage The expected message
|
||||
* @param otherProperties The expected inserts within the message
|
||||
* Evaluate the specified expression and ensure the expected message comes out.
|
||||
* The message may have inserts and they will be checked if otherProperties is specified.
|
||||
* The first entry in otherProperties should always be the position.
|
||||
* @param expression the expression to evaluate
|
||||
* @param expectedReturnType ask the expression return value to be of this type if possible
|
||||
* ({@code null} indicates don't ask for conversion)
|
||||
* @param expectedMessage the expected message
|
||||
* @param otherProperties the expected inserts within the message
|
||||
*/
|
||||
protected void evaluateAndCheckError(String expression, Class<?> expectedReturnType, SpelMessage expectedMessage,
|
||||
Object... otherProperties) {
|
||||
@@ -226,18 +184,16 @@ public abstract class ExpressionTestCase {
|
||||
fail("Parser returned null for expression");
|
||||
}
|
||||
if (expectedReturnType != null) {
|
||||
@SuppressWarnings("unused")
|
||||
Object value = expr.getValue(eContext, expectedReturnType);
|
||||
} else {
|
||||
@SuppressWarnings("unused")
|
||||
Object value = expr.getValue(eContext);
|
||||
expr.getValue(eContext, expectedReturnType);
|
||||
}
|
||||
else {
|
||||
expr.getValue(eContext);
|
||||
}
|
||||
fail("Should have failed with message " + expectedMessage);
|
||||
} catch (EvaluationException ee) {
|
||||
}
|
||||
catch (EvaluationException ee) {
|
||||
SpelEvaluationException ex = (SpelEvaluationException) ee;
|
||||
if (ex.getMessageCode() != expectedMessage) {
|
||||
// System.out.println(ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
assertEquals("Failed to get expected message", expectedMessage, ex.getMessageCode());
|
||||
}
|
||||
if (otherProperties != null && otherProperties.length != 0) {
|
||||
@@ -251,66 +207,49 @@ public abstract class ExpressionTestCase {
|
||||
inserts = new Object[0];
|
||||
}
|
||||
if (inserts.length < otherProperties.length - 1) {
|
||||
ex.printStackTrace();
|
||||
fail("Cannot check " + (otherProperties.length - 1)
|
||||
+ " properties of the exception, it only has " + inserts.length + " inserts");
|
||||
fail("Cannot check " + (otherProperties.length - 1) +
|
||||
" properties of the exception, it only has " + inserts.length + " inserts");
|
||||
}
|
||||
for (int i = 1; i < otherProperties.length; i++) {
|
||||
if (otherProperties[i] == null) {
|
||||
if (inserts[i - 1] != null) {
|
||||
ex.printStackTrace();
|
||||
fail("Insert does not match, expected 'null' but insert value was '" + inserts[i - 1]
|
||||
+ "'");
|
||||
fail("Insert does not match, expected 'null' but insert value was '" +
|
||||
inserts[i - 1] + "'");
|
||||
}
|
||||
} else if (inserts[i - 1] == null) {
|
||||
}
|
||||
else if (inserts[i - 1] == null) {
|
||||
if (otherProperties[i] != null) {
|
||||
ex.printStackTrace();
|
||||
fail("Insert does not match, expected '" + otherProperties[i]
|
||||
+ "' but insert value was 'null'");
|
||||
fail("Insert does not match, expected '" + otherProperties[i] +
|
||||
"' but insert value was 'null'");
|
||||
}
|
||||
} else if (!inserts[i - 1].equals(otherProperties[i])) {
|
||||
ex.printStackTrace();
|
||||
fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '"
|
||||
+ inserts[i - 1] + "'");
|
||||
}
|
||||
else if (!inserts[i - 1].equals(otherProperties[i])) {
|
||||
fail("Insert does not match, expected '" + otherProperties[i] +
|
||||
"' but insert value was '" + inserts[i - 1] + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ParseException pe) {
|
||||
pe.printStackTrace();
|
||||
fail("Unexpected Exception: " + pe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the specified expression and ensure the expected message comes out. The message may have inserts and they
|
||||
* will be checked if otherProperties is specified. The first entry in otherProperties should always be the
|
||||
* position.
|
||||
* @param expression The expression to evaluate
|
||||
* @param expectedMessage The expected message
|
||||
* @param otherProperties The expected inserts within the message
|
||||
* Parse the specified expression and ensure the expected message comes out.
|
||||
* The message may have inserts and they will be checked if otherProperties is specified.
|
||||
* The first entry in otherProperties should always be the position.
|
||||
* @param expression the expression to evaluate
|
||||
* @param expectedMessage the expected message
|
||||
* @param otherProperties the expected inserts within the message
|
||||
*/
|
||||
protected void parseAndCheckError(String expression, SpelMessage expectedMessage, Object... otherProperties) {
|
||||
try {
|
||||
Expression expr = parser.parseExpression(expression);
|
||||
SpelUtilities.printAbstractSyntaxTree(System.out, expr);
|
||||
fail("Parsing should have failed!");
|
||||
} catch (ParseException pe) {
|
||||
// pe.printStackTrace();
|
||||
// Throwable t = pe.getCause();
|
||||
// if (t == null) {
|
||||
// fail("ParseException caught with no defined cause");
|
||||
// }
|
||||
// if (!(t instanceof SpelEvaluationException)) {
|
||||
// t.printStackTrace();
|
||||
// fail("Cause of parse exception is not a SpelException");
|
||||
// }
|
||||
// SpelEvaluationException ex = (SpelEvaluationException) t;
|
||||
// pe.printStackTrace();
|
||||
}
|
||||
catch (ParseException pe) {
|
||||
SpelParseException ex = (SpelParseException)pe;
|
||||
if (ex.getMessageCode() != expectedMessage) {
|
||||
// System.out.println(ex.getMessage());
|
||||
ex.printStackTrace();
|
||||
assertEquals("Failed to get expected message", expectedMessage, ex.getMessageCode());
|
||||
}
|
||||
if (otherProperties != null && otherProperties.length != 0) {
|
||||
@@ -324,15 +263,13 @@ public abstract class ExpressionTestCase {
|
||||
inserts = new Object[0];
|
||||
}
|
||||
if (inserts.length < otherProperties.length - 1) {
|
||||
ex.printStackTrace();
|
||||
fail("Cannot check " + (otherProperties.length - 1)
|
||||
+ " properties of the exception, it only has " + inserts.length + " inserts");
|
||||
fail("Cannot check " + (otherProperties.length - 1) +
|
||||
" properties of the exception, it only has " + inserts.length + " inserts");
|
||||
}
|
||||
for (int i = 1; i < otherProperties.length; i++) {
|
||||
if (!inserts[i - 1].equals(otherProperties[i])) {
|
||||
ex.printStackTrace();
|
||||
fail("Insert does not match, expected '" + otherProperties[i] + "' but insert value was '"
|
||||
+ inserts[i - 1] + "'");
|
||||
fail("Insert does not match, expected '" + otherProperties[i] +
|
||||
"' but insert value was '" + inserts[i - 1] + "'");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -340,12 +277,13 @@ public abstract class ExpressionTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static String stringValueOf(Object value) {
|
||||
return stringValueOf(value, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Produce a nice string representation of the input object.
|
||||
*
|
||||
* @param value object to be formatted
|
||||
* @return a nice string
|
||||
*/
|
||||
@@ -368,7 +306,8 @@ public abstract class ExpressionTestCase {
|
||||
sb.append(stringValueOf(l[j]));
|
||||
}
|
||||
sb.append("}");
|
||||
} else if (primitiveType == Long.TYPE) {
|
||||
}
|
||||
else if (primitiveType == Long.TYPE) {
|
||||
long[] l = (long[]) value;
|
||||
sb.append("long[").append(l.length).append("]{");
|
||||
for (int j = 0; j < l.length; j++) {
|
||||
@@ -378,11 +317,13 @@ public abstract class ExpressionTestCase {
|
||||
sb.append(stringValueOf(l[j]));
|
||||
}
|
||||
sb.append("}");
|
||||
} else {
|
||||
throw new RuntimeException("Please implement support for type " + primitiveType.getName()
|
||||
+ " in ExpressionTestCase.stringValueOf()");
|
||||
}
|
||||
} else if (value.getClass().getComponentType().isArray()) {
|
||||
else {
|
||||
throw new RuntimeException("Please implement support for type " + primitiveType.getName() +
|
||||
" in ExpressionTestCase.stringValueOf()");
|
||||
}
|
||||
}
|
||||
else if (value.getClass().getComponentType().isArray()) {
|
||||
List<Object> l = Arrays.asList((Object[]) value);
|
||||
if (!isNested) {
|
||||
sb.append(value.getClass().getComponentType().getName());
|
||||
@@ -397,7 +338,8 @@ public abstract class ExpressionTestCase {
|
||||
sb.append(stringValueOf(object, true));
|
||||
}
|
||||
sb.append("}");
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
List<Object> l = Arrays.asList((Object[]) value);
|
||||
if (!isNested) {
|
||||
sb.append(value.getClass().getComponentType().getName());
|
||||
@@ -414,7 +356,8 @@ public abstract class ExpressionTestCase {
|
||||
sb.append("}");
|
||||
}
|
||||
return sb.toString();
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
return value.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -16,9 +16,6 @@
|
||||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertSame;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -26,8 +23,8 @@ import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.core.convert.TypeDescriptor;
|
||||
import org.springframework.expression.AccessException;
|
||||
import org.springframework.expression.BeanResolver;
|
||||
@@ -42,6 +39,8 @@ import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.testresources.PlaceOfBirth;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Tests invocation of methods.
|
||||
*
|
||||
@@ -55,17 +54,6 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
||||
evaluate("getPlaceOfBirth().getCity()", "SmilJan", String.class);
|
||||
}
|
||||
|
||||
// public void testBuiltInProcessors() {
|
||||
// evaluate("new int[]{1,2,3,4}.count()", 4, Integer.class);
|
||||
// evaluate("new int[]{4,3,2,1}.sort()[3]", 4, Integer.class);
|
||||
// evaluate("new int[]{4,3,2,1}.average()", 2, Integer.class);
|
||||
// evaluate("new int[]{4,3,2,1}.max()", 4, Integer.class);
|
||||
// evaluate("new int[]{4,3,2,1}.min()", 1, Integer.class);
|
||||
// evaluate("new int[]{4,3,2,1,2,3}.distinct().count()", 4, Integer.class);
|
||||
// evaluate("{1,2,3,null}.nonnull().count()", 3, Integer.class);
|
||||
// evaluate("new int[]{4,3,2,1,2,3}.distinct().count()", 4, Integer.class);
|
||||
// }
|
||||
|
||||
@Test
|
||||
public void testStringClass() {
|
||||
evaluate("new java.lang.String('hello').charAt(2)", 'l', Character.class);
|
||||
@@ -108,59 +96,57 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
||||
|
||||
// Normal exit
|
||||
StandardEvaluationContext eContext = TestScenarioCreator.getTestEvaluationContext();
|
||||
eContext.setVariable("bar",3);
|
||||
eContext.setVariable("bar", 3);
|
||||
Object o = expr.getValue(eContext);
|
||||
Assert.assertEquals(o,3);
|
||||
Assert.assertEquals(1,parser.parseExpression("counter").getValue(eContext));
|
||||
assertEquals(o, 3);
|
||||
assertEquals(1, parser.parseExpression("counter").getValue(eContext));
|
||||
|
||||
// Now the expression has cached that throwException(int) is the right thing to call
|
||||
// Let's change 'bar' to be a PlaceOfBirth which indicates the cached reference is
|
||||
// out of date.
|
||||
eContext.setVariable("bar",new PlaceOfBirth("London"));
|
||||
eContext.setVariable("bar", new PlaceOfBirth("London"));
|
||||
o = expr.getValue(eContext);
|
||||
Assert.assertEquals("London", o);
|
||||
assertEquals("London", o);
|
||||
// That confirms the logic to mark the cached reference stale and retry is working
|
||||
|
||||
|
||||
// Now let's cause the method to exit via exception and ensure it doesn't cause
|
||||
// a retry.
|
||||
// Now let's cause the method to exit via exception and ensure it doesn't cause a retry.
|
||||
|
||||
// First, switch back to throwException(int)
|
||||
eContext.setVariable("bar",3);
|
||||
eContext.setVariable("bar", 3);
|
||||
o = expr.getValue(eContext);
|
||||
Assert.assertEquals(3, o);
|
||||
Assert.assertEquals(2,parser.parseExpression("counter").getValue(eContext));
|
||||
assertEquals(3, o);
|
||||
assertEquals(2, parser.parseExpression("counter").getValue(eContext));
|
||||
|
||||
|
||||
// Now cause it to throw an exception:
|
||||
eContext.setVariable("bar",1);
|
||||
eContext.setVariable("bar", 1);
|
||||
try {
|
||||
o = expr.getValue(eContext);
|
||||
Assert.fail();
|
||||
} catch (Exception e) {
|
||||
if (e instanceof SpelEvaluationException) {
|
||||
e.printStackTrace();
|
||||
Assert.fail("Should not be a SpelEvaluationException");
|
||||
fail();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof SpelEvaluationException) {
|
||||
fail("Should not be a SpelEvaluationException: " + ex);
|
||||
}
|
||||
// normal
|
||||
}
|
||||
// If counter is 4 then the method got called twice!
|
||||
Assert.assertEquals(3,parser.parseExpression("counter").getValue(eContext));
|
||||
assertEquals(3, parser.parseExpression("counter").getValue(eContext));
|
||||
|
||||
eContext.setVariable("bar",4);
|
||||
eContext.setVariable("bar", 4);
|
||||
try {
|
||||
o = expr.getValue(eContext);
|
||||
Assert.fail();
|
||||
} catch (Exception e) {
|
||||
fail();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
// 4 means it will throw a checked exception - this will be wrapped
|
||||
if (!(e instanceof ExpressionInvocationTargetException)) {
|
||||
e.printStackTrace();
|
||||
Assert.fail("Should have been wrapped");
|
||||
if (!(ex instanceof ExpressionInvocationTargetException)) {
|
||||
fail("Should have been wrapped: " + ex);
|
||||
}
|
||||
// normal
|
||||
}
|
||||
// If counter is 5 then the method got called twice!
|
||||
Assert.assertEquals(4,parser.parseExpression("counter").getValue(eContext));
|
||||
assertEquals(4, parser.parseExpression("counter").getValue(eContext));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,14 +163,14 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expr = parser.parseExpression("throwException(#bar)");
|
||||
|
||||
eContext.setVariable("bar",2);
|
||||
eContext.setVariable("bar", 2);
|
||||
try {
|
||||
expr.getValue(eContext);
|
||||
Assert.fail();
|
||||
} catch (Exception e) {
|
||||
if (e instanceof SpelEvaluationException) {
|
||||
e.printStackTrace();
|
||||
Assert.fail("Should not be a SpelEvaluationException");
|
||||
fail();
|
||||
}
|
||||
catch (Exception ex) {
|
||||
if (ex instanceof SpelEvaluationException) {
|
||||
fail("Should not be a SpelEvaluationException: " + ex);
|
||||
}
|
||||
// normal
|
||||
}
|
||||
@@ -201,16 +187,16 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expr = parser.parseExpression("throwException(#bar)");
|
||||
|
||||
eContext.setVariable("bar",4);
|
||||
eContext.setVariable("bar", 4);
|
||||
try {
|
||||
expr.getValue(eContext);
|
||||
Assert.fail();
|
||||
} catch (ExpressionInvocationTargetException e) {
|
||||
Throwable t = e.getCause();
|
||||
Assert.assertEquals("org.springframework.expression.spel.testresources.Inventor$TestException", t.getClass().getName());
|
||||
return;
|
||||
fail();
|
||||
}
|
||||
catch (ExpressionInvocationTargetException ex) {
|
||||
Throwable cause = ex.getCause();
|
||||
assertEquals("org.springframework.expression.spel.testresources.Inventor$TestException",
|
||||
cause.getClass().getName());
|
||||
}
|
||||
Assert.fail("Should not be a SpelEvaluationException");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -223,87 +209,34 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
||||
|
||||
// Filter will be called but not do anything, so first doit() will be invoked
|
||||
SpelExpression expr = (SpelExpression) parser.parseExpression("doit(1)");
|
||||
String result = expr.getValue(context,String.class);
|
||||
Assert.assertEquals("1",result);
|
||||
Assert.assertTrue(filter.filterCalled);
|
||||
String result = expr.getValue(context, String.class);
|
||||
assertEquals("1", result);
|
||||
assertTrue(filter.filterCalled);
|
||||
|
||||
// Filter will now remove non @Anno annotated methods
|
||||
filter.removeIfNotAnnotated = true;
|
||||
filter.filterCalled = false;
|
||||
expr = (SpelExpression) parser.parseExpression("doit(1)");
|
||||
result = expr.getValue(context,String.class);
|
||||
Assert.assertEquals("double 1.0",result);
|
||||
Assert.assertTrue(filter.filterCalled);
|
||||
result = expr.getValue(context, String.class);
|
||||
assertEquals("double 1.0", result);
|
||||
assertTrue(filter.filterCalled);
|
||||
|
||||
// check not called for other types
|
||||
filter.filterCalled=false;
|
||||
filter.filterCalled = false;
|
||||
context.setRootObject(new String("abc"));
|
||||
expr = (SpelExpression) parser.parseExpression("charAt(0)");
|
||||
result = expr.getValue(context,String.class);
|
||||
Assert.assertEquals("a",result);
|
||||
Assert.assertFalse(filter.filterCalled);
|
||||
result = expr.getValue(context, String.class);
|
||||
assertEquals("a", result);
|
||||
assertFalse(filter.filterCalled);
|
||||
|
||||
// check de-registration works
|
||||
filter.filterCalled = false;
|
||||
context.registerMethodFilter(TestObject.class,null);//clear filter
|
||||
context.setRootObject(new TestObject());
|
||||
expr = (SpelExpression) parser.parseExpression("doit(1)");
|
||||
result = expr.getValue(context,String.class);
|
||||
Assert.assertEquals("1",result);
|
||||
Assert.assertFalse(filter.filterCalled);
|
||||
}
|
||||
|
||||
// Simple filter
|
||||
static class LocalFilter implements MethodFilter {
|
||||
|
||||
public boolean removeIfNotAnnotated = false;
|
||||
|
||||
public boolean filterCalled = false;
|
||||
|
||||
private boolean isAnnotated(Method m) {
|
||||
Annotation[] annos = m.getAnnotations();
|
||||
if (annos==null) {
|
||||
return false;
|
||||
}
|
||||
for (Annotation anno: annos) {
|
||||
String s = anno.annotationType().getName();
|
||||
if (s.endsWith("Anno")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Method> filter(List<Method> methods) {
|
||||
filterCalled = true;
|
||||
List<Method> forRemoval = new ArrayList<Method>();
|
||||
for (Method m: methods) {
|
||||
if (removeIfNotAnnotated && !isAnnotated(m)) {
|
||||
forRemoval.add(m);
|
||||
}
|
||||
}
|
||||
for (Method m: forRemoval) {
|
||||
methods.remove(m);
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Anno {}
|
||||
|
||||
class TestObject {
|
||||
public int doit(int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Anno
|
||||
public String doit(double d) {
|
||||
return "double "+d;
|
||||
}
|
||||
|
||||
result = expr.getValue(context, String.class);
|
||||
assertEquals("1", result);
|
||||
assertFalse(filter.filterCalled);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -312,33 +245,22 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
||||
|
||||
// reflective method accessor is the only one by default
|
||||
List<MethodResolver> methodResolvers = ctx.getMethodResolvers();
|
||||
Assert.assertEquals(1,methodResolvers.size());
|
||||
assertEquals(1, methodResolvers.size());
|
||||
|
||||
MethodResolver dummy = new DummyMethodResolver();
|
||||
ctx.addMethodResolver(dummy);
|
||||
Assert.assertEquals(2,ctx.getMethodResolvers().size());
|
||||
assertEquals(2, ctx.getMethodResolvers().size());
|
||||
|
||||
List<MethodResolver> copy = new ArrayList<MethodResolver>();
|
||||
copy.addAll(ctx.getMethodResolvers());
|
||||
Assert.assertTrue(ctx.removeMethodResolver(dummy));
|
||||
Assert.assertFalse(ctx.removeMethodResolver(dummy));
|
||||
Assert.assertEquals(1,ctx.getMethodResolvers().size());
|
||||
assertTrue(ctx.removeMethodResolver(dummy));
|
||||
assertFalse(ctx.removeMethodResolver(dummy));
|
||||
assertEquals(1, ctx.getMethodResolvers().size());
|
||||
|
||||
ctx.setMethodResolvers(copy);
|
||||
Assert.assertEquals(2,ctx.getMethodResolvers().size());
|
||||
assertEquals(2, ctx.getMethodResolvers().size());
|
||||
}
|
||||
|
||||
static class DummyMethodResolver implements MethodResolver {
|
||||
|
||||
@Override
|
||||
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
|
||||
List<TypeDescriptor> argumentTypes) throws AccessException {
|
||||
throw new UnsupportedOperationException("Auto-generated method stub");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testVarargsInvocation01() {
|
||||
// Calling 'public int aVarargsMethod(String... strings)'
|
||||
@@ -382,8 +304,7 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
||||
StandardEvaluationContext context = new StandardEvaluationContext(bytes);
|
||||
context.setBeanResolver(new BeanResolver() {
|
||||
@Override
|
||||
public Object resolve(EvaluationContext context, String beanName)
|
||||
throws AccessException {
|
||||
public Object resolve(EvaluationContext context, String beanName) throws AccessException {
|
||||
if ("service".equals(beanName)) {
|
||||
return service;
|
||||
}
|
||||
@@ -395,10 +316,78 @@ public class MethodInvocationTests extends ExpressionTestCase {
|
||||
assertSame(bytes, outBytes);
|
||||
}
|
||||
|
||||
|
||||
// Simple filter
|
||||
static class LocalFilter implements MethodFilter {
|
||||
|
||||
public boolean removeIfNotAnnotated = false;
|
||||
|
||||
public boolean filterCalled = false;
|
||||
|
||||
private boolean isAnnotated(Method method) {
|
||||
Annotation[] anns = method.getAnnotations();
|
||||
if (anns == null) {
|
||||
return false;
|
||||
}
|
||||
for (Annotation ann : anns) {
|
||||
String name = ann.annotationType().getName();
|
||||
if (name.endsWith("Anno")) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Method> filter(List<Method> methods) {
|
||||
filterCalled = true;
|
||||
List<Method> forRemoval = new ArrayList<Method>();
|
||||
for (Method method: methods) {
|
||||
if (removeIfNotAnnotated && !isAnnotated(method)) {
|
||||
forRemoval.add(method);
|
||||
}
|
||||
}
|
||||
for (Method method: forRemoval) {
|
||||
methods.remove(method);
|
||||
}
|
||||
return methods;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface Anno {
|
||||
}
|
||||
|
||||
|
||||
class TestObject {
|
||||
|
||||
public int doit(int i) {
|
||||
return i;
|
||||
}
|
||||
|
||||
@Anno
|
||||
public String doit(double d) {
|
||||
return "double "+d;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static class DummyMethodResolver implements MethodResolver {
|
||||
|
||||
@Override
|
||||
public MethodExecutor resolve(EvaluationContext context, Object targetObject, String name,
|
||||
List<TypeDescriptor> argumentTypes) throws AccessException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class BytesService {
|
||||
|
||||
public byte[] handleBytes(byte[] bytes) {
|
||||
return bytes;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2009 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -22,9 +22,9 @@ import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.expression.spel.testresources.Inventor;
|
||||
import org.springframework.expression.spel.testresources.PlaceOfBirth;
|
||||
|
||||
///CLOVER:OFF
|
||||
/**
|
||||
* Builds an evaluation context for test expressions. Features of the test evaluation context are:
|
||||
* Builds an evaluation context for test expressions.
|
||||
* Features of the test evaluation context are:
|
||||
* <ul>
|
||||
* <li>The root context object is an Inventor instance {@link Inventor}
|
||||
* </ul>
|
||||
@@ -45,21 +45,19 @@ public class TestScenarioCreator {
|
||||
*/
|
||||
private static void populateFunctions(StandardEvaluationContext testContext) {
|
||||
try {
|
||||
testContext.registerFunction("isEven", TestScenarioCreator.class.getDeclaredMethod("isEven",
|
||||
new Class[] { Integer.TYPE }));
|
||||
testContext.registerFunction("reverseInt", TestScenarioCreator.class.getDeclaredMethod("reverseInt",
|
||||
new Class[] { Integer.TYPE, Integer.TYPE, Integer.TYPE }));
|
||||
testContext.registerFunction("reverseString", TestScenarioCreator.class.getDeclaredMethod("reverseString",
|
||||
new Class[] { String.class }));
|
||||
testContext.registerFunction("varargsFunctionReverseStringsAndMerge", TestScenarioCreator.class
|
||||
.getDeclaredMethod("varargsFunctionReverseStringsAndMerge", new Class[] { String[].class }));
|
||||
testContext.registerFunction("varargsFunctionReverseStringsAndMerge2", TestScenarioCreator.class
|
||||
.getDeclaredMethod("varargsFunctionReverseStringsAndMerge2", new Class[] { Integer.TYPE,
|
||||
String[].class }));
|
||||
} catch (SecurityException e) {
|
||||
e.printStackTrace();
|
||||
} catch (NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
testContext.registerFunction("isEven",
|
||||
TestScenarioCreator.class.getDeclaredMethod("isEven", Integer.TYPE));
|
||||
testContext.registerFunction("reverseInt",
|
||||
TestScenarioCreator.class.getDeclaredMethod("reverseInt", Integer.TYPE, Integer.TYPE, Integer.TYPE));
|
||||
testContext.registerFunction("reverseString",
|
||||
TestScenarioCreator.class.getDeclaredMethod("reverseString", String.class));
|
||||
testContext.registerFunction("varargsFunctionReverseStringsAndMerge",
|
||||
TestScenarioCreator.class.getDeclaredMethod("varargsFunctionReverseStringsAndMerge", String[].class));
|
||||
testContext.registerFunction("varargsFunctionReverseStringsAndMerge2",
|
||||
TestScenarioCreator.class.getDeclaredMethod("varargsFunctionReverseStringsAndMerge2", Integer.TYPE, String[].class));
|
||||
}
|
||||
catch (Exception ex) {
|
||||
throw new IllegalStateException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,9 +70,8 @@ public class TestScenarioCreator {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the root context object, an Inventor instance. Non-qualified property and method references will be
|
||||
* resolved against this context object.
|
||||
*
|
||||
* Create the root context object, an Inventor instance. Non-qualified property
|
||||
* and method references will be resolved against this context object.
|
||||
* @param testContext the evaluation context in which to set the root object
|
||||
*/
|
||||
private static void setupRootContextObject(StandardEvaluationContext testContext) {
|
||||
@@ -88,12 +85,14 @@ public class TestScenarioCreator {
|
||||
testContext.setRootObject(tesla);
|
||||
}
|
||||
|
||||
|
||||
// These methods are registered in the test context and therefore accessible through function calls
|
||||
// in test expressions
|
||||
|
||||
public static String isEven(int i) {
|
||||
if ((i % 2) == 0)
|
||||
if ((i % 2) == 0) {
|
||||
return "y";
|
||||
}
|
||||
return "n";
|
||||
}
|
||||
|
||||
@@ -129,4 +128,5 @@ public class TestScenarioCreator {
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user