Browse Source

SPR-5673: more intelligence in TemplateAwareExpressionParser. Supports prefix/suffix escaping and nesting of prefixes/suffixes

git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@1000 50f2f4bb-b051-0410-bef5-90022cba6387
pull/1/head
Andy Clement 17 years ago
parent
commit
3e60a76e6b
  1. 2
      org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java
  2. 2
      org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java
  3. 7
      org.springframework.expression/src/test/java/org/springframework/expression/spel/InProgressTests.java
  4. 12
      org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java
  5. 74
      org.springframework.expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java

2
org.springframework.expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java

File diff suppressed because one or more lines are too long

2
org.springframework.expression/src/main/java/org/springframework/expression/spel/ast/Selection.java

@ -123,7 +123,7 @@ public class Selection extends SpelNodeImpl { @@ -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()));

7
org.springframework.expression/src/test/java/org/springframework/expression/spel/InProgressTests.java

@ -352,6 +352,7 @@ public class InProgressTests extends ExpressionTestCase { @@ -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 { @@ -386,10 +387,4 @@ public class InProgressTests extends ExpressionTestCase {
assertFalse(expr.isWritable(new StandardEvaluationContext()));
}
}

12
org.springframework.expression/src/test/java/org/springframework/expression/spel/SpringEL300Tests.java

@ -16,6 +16,9 @@ @@ -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 { @@ -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"))));
}
}

74
org.springframework.expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java

@ -41,6 +41,17 @@ public class TemplateExpressionParsingTests extends ExpressionTestCase { @@ -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 { @@ -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 { @@ -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 { @@ -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());
// }
}

Loading…
Cancel
Save