SPR-5673: fix for problems with expressions that use the same symbols as are used in the template prefix/suffix

This commit is contained in:
Andy Clement
2009-04-22 00:10:47 +00:00
parent dfa4b3e397
commit 4c42597cbc
4 changed files with 85 additions and 12 deletions

View File

@@ -95,5 +95,9 @@ public class CompositeStringExpression implements Expression {
public boolean isWritable(EvaluationContext context) {
return false;
}
public Expression[] getExpressions() {
return expressions;
}
}

View File

@@ -17,6 +17,7 @@
package org.springframework.expression.spel;
import org.springframework.expression.Expression;
import org.springframework.expression.ParserContext;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
/**
@@ -26,20 +27,82 @@ import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
*/
public class SpringEL300Tests extends ExpressionTestCase {
public static final ParserContext DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT = new ParserContext() {
public String getExpressionPrefix() {
return "$[";
}
public String getExpressionSuffix() {
return "]";
}
public boolean isTemplate() {
return true;
}
};
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());
ParserContext hashes = TemplateExpressionParsingTests.HASH_DELIMITED_PARSER_CONTEXT;
ParserContext dollars = TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT;
ex = parser.parseExpression("This is the last odd number in the list: ${listOfNumbersUpToTen.$[#this%2==1]}",TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT);
assertEquals("This is the last odd number in the list: 9",ex.getValue(TestScenarioCreator.getTestEvaluationContext()));
checkTemplateParsing("abc${'def'} ghi","abcdef ghi");
checkTemplateParsingError("abc${ {}( 'abc'","Missing closing ')' for '(' at position 8");
checkTemplateParsingError("abc${ {}[ 'abc'","Missing closing ']' for '[' at position 8");
checkTemplateParsingError("abc${ {}{ 'abc'","Missing closing '}' for '{' at position 8");
checkTemplateParsingError("abc${ ( 'abc' }","Found closing '}' at position 14 but most recent opening is '(' at position 6");
checkTemplateParsingError("abc${ '... }","Found non terminating string literal starting at position 6");
checkTemplateParsingError("abc${ \"... }","Found non terminating string literal starting at position 6");
checkTemplateParsingError("abc${ ) }","Found closing ')' at position 6 without an opening '('");
checkTemplateParsingError("abc${ ] }","Found closing ']' at position 6 without an opening '['");
checkTemplateParsingError("abc${ } }","No expression defined within delimiter '${}' at character 3");
checkTemplateParsingError("abc$[ } ]",DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT,"Found closing '}' at position 6 without an opening '{'");
checkTemplateParsing("abc ${\"def''g}hi\"} jkl","abc def'g}hi jkl");
checkTemplateParsing("abc ${'def''g}hi'} jkl","abc def'g}hi jkl");
checkTemplateParsing("}","}");
checkTemplateParsing("${'hello'} world","hello world");
checkTemplateParsing("Hello ${'}'}]","Hello }]");
checkTemplateParsing("Hello ${'}'}","Hello }");
checkTemplateParsingError("Hello ${ ( ","No ending suffix '}' for expression starting at character 6: ${ ( ");
checkTemplateParsingError("Hello ${ ( }","Found closing '}' at position 11 but most recent opening is '(' at position 9");
checkTemplateParsing("#{'Unable to render embedded object: File ({#this == 2}'}", hashes,"Unable to render embedded object: File ({#this == 2}");
checkTemplateParsing("This is the last odd number in the list: ${listOfNumbersUpToTen.$[#this%2==1]}",dollars,"This is the last odd number in the list: 9");
checkTemplateParsing("Hello ${'here is a curly bracket }'}",dollars,"Hello here is a curly bracket }");
checkTemplateParsing("He${'${'}llo ${'here is a curly bracket }'}}",dollars,"He${llo here is a curly bracket }}");
checkTemplateParsing("Hello ${'()()()}{}{}{][]{}{][}[][][}{()()'} World",dollars,"Hello ()()()}{}{}{][]{}{][}[][][}{()() World");
checkTemplateParsing("Hello ${'inner literal that''s got {[(])]}an escaped quote in it'} World","Hello inner literal that's got {[(])]}an escaped quote in it World");
checkTemplateParsingError("Hello ${","No ending suffix '}' for expression starting at character 6: ${");
}
ex = parser.parseExpression("Hello ${'here is a curly bracket \\}'}",TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT);
assertEquals("Hello here is a curly bracket }",ex.getValue());
private void checkTemplateParsing(String expression, String expectedValue) throws Exception {
checkTemplateParsing(expression,TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT, expectedValue);
}
private void checkTemplateParsing(String expression, ParserContext context, String expectedValue) throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser();
Expression expr = parser.parseExpression(expression,context);
assertEquals(expectedValue,expr.getValue(TestScenarioCreator.getTestEvaluationContext()));
}
private void checkTemplateParsingError(String expression,String expectedMessage) throws Exception {
checkTemplateParsingError(expression, TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT,expectedMessage);
}
private void checkTemplateParsingError(String expression,ParserContext context, String expectedMessage) throws Exception {
SpelAntlrExpressionParser parser = new SpelAntlrExpressionParser();
try {
Expression expr = parser.parseExpression(expression,context);
fail("Should have failed");
} catch (Exception e) {
if (!e.getMessage().equals(expectedMessage)) {
e.printStackTrace();
}
assertEquals(expectedMessage,e.getMessage());
}
}
}

View File

@@ -20,6 +20,7 @@ import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ParseException;
import org.springframework.expression.ParserContext;
import org.springframework.expression.common.CompositeStringExpression;
import org.springframework.expression.spel.antlr.SpelAntlrExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
@@ -111,6 +112,11 @@ public class TemplateExpressionParsingTests extends ExpressionTestCase {
// 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);
assertEquals(CompositeStringExpression.class,ex.getClass());
CompositeStringExpression cse = (CompositeStringExpression)ex;
Expression[] exprs = cse.getExpressions();
assertEquals(3,exprs.length);
assertEquals("listOfNumbersUpToTen.$[#root.listOfNumbersUpToTen.$[#this%2==1]==3]",exprs[1].getExpressionString());
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
assertEquals("hello world",s);
@@ -126,10 +132,10 @@ public class TemplateExpressionParsingTests extends ExpressionTestCase {
}
try {
ex = parser.parseExpression("hello ${listOfNumbersUpToTen.${#root.listOfNumbersUpToTen.${#this%2==1==3}} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
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());
assertEquals("Found closing '}' at position 74 but most recent opening is '[' at position 30",pe.getMessage());
}
}
@@ -139,11 +145,11 @@ public class TemplateExpressionParsingTests extends ExpressionTestCase {
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);
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);
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);
}