SPR-5673: more intelligence in TemplateAwareExpressionParser. Supports prefix/suffix escaping and nesting of prefixes/suffixes
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -123,7 +123,7 @@ public class Selection extends SpelNodeImpl {
|
||||
}
|
||||
}
|
||||
if ((variant == FIRST || variant == LAST) && result.size() == 0) {
|
||||
return null;
|
||||
return TypedValue.NULL_TYPED_VALUE;
|
||||
}
|
||||
if (variant == LAST) {
|
||||
return new TypedValue(result.get(result.size() - 1),TypeDescriptor.valueOf(op.getTypeDescriptor().getElementType()));
|
||||
|
||||
@@ -352,6 +352,7 @@ public class InProgressTests extends ExpressionTestCase {
|
||||
|
||||
public void testSelection03() {
|
||||
evaluate("mapOfNumbersUpToTen.?{key>5}.size()", "5", Integer.class);
|
||||
// evaluate("listOfNumbersUpToTen.?{#this>5}", "5", ArrayList.class);
|
||||
}
|
||||
|
||||
public void testSelection04() {
|
||||
@@ -386,10 +387,4 @@ public class InProgressTests extends ExpressionTestCase {
|
||||
assertFalse(expr.isWritable(new StandardEvaluationContext()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
|
||||
package org.springframework.expression.spel;
|
||||
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
|
||||
|
||||
/**
|
||||
* Tests based on Jiras up to the release of Spring 3.0.0
|
||||
*
|
||||
@@ -26,5 +29,14 @@ public class SpringEL300Tests extends ExpressionTestCase {
|
||||
public void testNPE_5661() {
|
||||
evaluate("joinThreeStrings('a',null,'c')", "anullc", String.class);
|
||||
}
|
||||
|
||||
public void testNPE_5673() throws Exception {
|
||||
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
Expression ex = parser.parseExpression("#{'Unable to render embedded object: File ({#this == 2\\}'}", TemplateExpressionParsingTests.HASH_DELIMITED_PARSER_CONTEXT);
|
||||
assertEquals("Unable to render embedded object: File ({#this == 2}",ex.getValue());
|
||||
// ex = parser.parseExpression("Unable to render embedded object: File (#{#this}) not found", TemplateExpressionParsingTests.HASH_DELIMITED_PARSER_CONTEXT);
|
||||
// assertEquals()
|
||||
// System.out.println(ex.getValue(new StandardEvaluationContext(new File("C:/temp"))));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -41,6 +41,17 @@ public class TemplateExpressionParsingTests extends ExpressionTestCase {
|
||||
}
|
||||
};
|
||||
|
||||
public static final ParserContext HASH_DELIMITED_PARSER_CONTEXT = new ParserContext() {
|
||||
public String getExpressionPrefix() {
|
||||
return "#{";
|
||||
}
|
||||
public String getExpressionSuffix() {
|
||||
return "}";
|
||||
}
|
||||
public boolean isTemplate() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public void testParsingSimpleTemplateExpression01() throws Exception {
|
||||
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
@@ -91,6 +102,52 @@ public class TemplateExpressionParsingTests extends ExpressionTestCase {
|
||||
assertFalse(ex.isWritable(new StandardEvaluationContext()));
|
||||
}
|
||||
|
||||
public void testNestedExpressions() throws Exception {
|
||||
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser();
|
||||
// treat the nested ${..} as a part of the expression
|
||||
Expression ex = parser.parseExpression("hello ${listOfNumbersUpToTen.${#this<5}} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
String s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertEquals("hello 4 world",s);
|
||||
|
||||
// not a useful expression but tests nested expression syntax that clashes with template prefix/suffix
|
||||
ex = parser.parseExpression("hello ${listOfNumbersUpToTen.${#root.listOfNumbersUpToTen.${#this%2==1}==3}} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertEquals("hello world",s);
|
||||
|
||||
ex = parser.parseExpression("hello ${listOfNumbersUpToTen.${#this<5}} ${listOfNumbersUpToTen.${#this>5}} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertEquals("hello 4 10 world",s);
|
||||
|
||||
try {
|
||||
ex = parser.parseExpression("hello ${listOfNumbersUpToTen.${#this<5}} ${listOfNumbersUpToTen.${#this>5} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
fail("Should have failed");
|
||||
} catch (ParseException pe) {
|
||||
assertEquals("No ending suffix '}' for expression starting at character 41: ${listOfNumbersUpToTen.${#this>5} world",pe.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
ex = parser.parseExpression("hello ${listOfNumbersUpToTen.${#root.listOfNumbersUpToTen.${#this%2==1==3}} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
fail("Should have failed");
|
||||
} catch (ParseException pe) {
|
||||
assertEquals("No ending suffix '}' for expression starting at character 6: ${listOfNumbersUpToTen.${#root.listOfNumbersUpToTen.${#this%2==1==3}} world",pe.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void testClashingWithSuffixes() throws Exception {
|
||||
// Just wanting to use the prefix or suffix within the template:
|
||||
Expression ex = parser.parseExpression("hello ${3+4} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
String s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertEquals("hello 7 world",s);
|
||||
|
||||
ex = parser.parseExpression("hello ${3+4} wo\\${rld",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertEquals("hello 7 wo${rld",s);
|
||||
|
||||
ex = parser.parseExpression("hello ${3+4} wo\\}rld",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertEquals("hello 7 wo}rld",s);
|
||||
}
|
||||
|
||||
public void testParsingNormalExpressionThroughTemplateParser() throws Exception {
|
||||
Expression expr = parser.parseExpression("1+2+3");
|
||||
assertEquals(6,expr.getValue());
|
||||
@@ -117,10 +174,12 @@ public class TemplateExpressionParsingTests extends ExpressionTestCase {
|
||||
fail("Should have failed");
|
||||
} catch (ParseException pe) {
|
||||
assertEquals("No expression defined within delimiter '${}' at character 6",pe.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ---
|
||||
|
||||
private void checkString(String expectedString, Object value) {
|
||||
if (!(value instanceof String)) {
|
||||
fail("Result was not a string, it was of type " + value.getClass() + " (value=" + value + ")");
|
||||
@@ -130,15 +189,4 @@ public class TemplateExpressionParsingTests extends ExpressionTestCase {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO need to support this case but what is the neatest way? Escape the clashing delimiters in the expression
|
||||
// string?
|
||||
// public void testParsingTemplateExpressionThatEmbedsTheDelimiters() throws Exception {
|
||||
// SpelExpressionParser parser = new SpelExpressionParser();
|
||||
// Expression expr = parser.parseExpression("The quick ${{'green','brown'}.${true}} fox jumped over the ${'lazy'}
|
||||
// dog",DefaultTemplateParserContext.INSTANCE);
|
||||
// Object o = expr.getValue();
|
||||
// System.out.println(o);
|
||||
// assertEquals("The quick brown fox jumped over the lazy dog",o.toString());
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user