Polishing
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -27,10 +27,11 @@ package org.springframework.expression;
|
||||
public interface ParserContext {
|
||||
|
||||
/**
|
||||
* Whether the expression being parsed is a template. A template expression
|
||||
* consists of literal text that can be mixed with evaluatable blocks. Some examples:
|
||||
* Whether the expression being parsed is a template.
|
||||
* <p>A template consists of literal text that can be mixed with expressions.
|
||||
* Some examples:
|
||||
* <pre class="code">
|
||||
* Some literal text
|
||||
* Some literal text
|
||||
* Hello #{name.firstName}!
|
||||
* #{3 + 4}
|
||||
* </pre>
|
||||
|
||||
@@ -51,6 +51,7 @@ import org.springframework.expression.MethodResolver;
|
||||
import org.springframework.expression.ParserContext;
|
||||
import org.springframework.expression.PropertyAccessor;
|
||||
import org.springframework.expression.TypedValue;
|
||||
import org.springframework.expression.common.TemplateParserContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpression;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.ReflectiveMethodResolver;
|
||||
@@ -77,6 +78,9 @@ import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
*/
|
||||
class SpelReproTests extends AbstractExpressionTests {
|
||||
|
||||
private static final ParserContext DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT = new TemplateParserContext("$[", "]");
|
||||
|
||||
|
||||
@Test
|
||||
void NPE_SPR5661() {
|
||||
evaluate("joinThreeStrings('a',null,'c')", "anullc", String.class);
|
||||
@@ -193,8 +197,8 @@ class SpelReproTests extends AbstractExpressionTests {
|
||||
|
||||
@Test
|
||||
void NPE_SPR5673() {
|
||||
ParserContext hashes = TemplateExpressionParsingTests.HASH_DELIMITED_PARSER_CONTEXT;
|
||||
ParserContext dollars = TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT;
|
||||
ParserContext hashes = ParserContext.TEMPLATE_EXPRESSION;
|
||||
ParserContext dollars = TemplateExpressionParsingTests.DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT;
|
||||
|
||||
checkTemplateParsing("abc${'def'} ghi", "abcdef ghi");
|
||||
|
||||
@@ -378,7 +382,7 @@ class SpelReproTests extends AbstractExpressionTests {
|
||||
}
|
||||
|
||||
private void checkTemplateParsing(String expression, String expectedValue) {
|
||||
checkTemplateParsing(expression, TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT, expectedValue);
|
||||
checkTemplateParsing(expression, TemplateExpressionParsingTests.DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT, expectedValue);
|
||||
}
|
||||
|
||||
private void checkTemplateParsing(String expression, ParserContext context, String expectedValue) {
|
||||
@@ -388,7 +392,7 @@ class SpelReproTests extends AbstractExpressionTests {
|
||||
}
|
||||
|
||||
private void checkTemplateParsingError(String expression, String expectedMessage) {
|
||||
checkTemplateParsingError(expression, TemplateExpressionParsingTests.DEFAULT_TEMPLATE_PARSER_CONTEXT, expectedMessage);
|
||||
checkTemplateParsingError(expression, TemplateExpressionParsingTests.DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT, expectedMessage);
|
||||
}
|
||||
|
||||
private void checkTemplateParsingError(String expression, ParserContext context, String expectedMessage) {
|
||||
@@ -404,22 +408,6 @@ class SpelReproTests extends AbstractExpressionTests {
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private static final ParserContext DOLLARSQUARE_TEMPLATE_PARSER_CONTEXT = new ParserContext() {
|
||||
@Override
|
||||
public String getExpressionPrefix() {
|
||||
return "$[";
|
||||
}
|
||||
@Override
|
||||
public String getExpressionSuffix() {
|
||||
return "]";
|
||||
}
|
||||
@Override
|
||||
public boolean isTemplate() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
@Test
|
||||
void beanResolution() {
|
||||
StandardEvaluationContext context = new StandardEvaluationContext(new XX());
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2022 the original author or authors.
|
||||
* Copyright 2002-2023 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.
|
||||
@@ -34,89 +34,62 @@ import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
|
||||
/**
|
||||
* @author Andy Clement
|
||||
* @author Juergen Hoeller
|
||||
* @author Sam Brannen
|
||||
*/
|
||||
public class TemplateExpressionParsingTests extends AbstractExpressionTests {
|
||||
class TemplateExpressionParsingTests extends AbstractExpressionTests {
|
||||
|
||||
public static final ParserContext DEFAULT_TEMPLATE_PARSER_CONTEXT = new ParserContext() {
|
||||
@Override
|
||||
public String getExpressionPrefix() {
|
||||
return "${";
|
||||
}
|
||||
@Override
|
||||
public String getExpressionSuffix() {
|
||||
return "}";
|
||||
}
|
||||
@Override
|
||||
public boolean isTemplate() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
public static final ParserContext HASH_DELIMITED_PARSER_CONTEXT = new ParserContext() {
|
||||
@Override
|
||||
public String getExpressionPrefix() {
|
||||
return "#{";
|
||||
}
|
||||
@Override
|
||||
public String getExpressionSuffix() {
|
||||
return "}";
|
||||
}
|
||||
@Override
|
||||
public boolean isTemplate() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
static final ParserContext DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT = new TemplateParserContext("${", "}");
|
||||
|
||||
|
||||
@Test
|
||||
public void testParsingSimpleTemplateExpression01() throws Exception {
|
||||
void parsingSimpleTemplateExpression01() throws Exception {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expr = parser.parseExpression("hello ${'world'}", DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
Expression expr = parser.parseExpression("hello ${'world'}", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
Object o = expr.getValue();
|
||||
assertThat(o.toString()).isEqualTo("hello world");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsingSimpleTemplateExpression02() throws Exception {
|
||||
void parsingSimpleTemplateExpression02() throws Exception {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expr = parser.parseExpression("hello ${'to'} you", DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
Expression expr = parser.parseExpression("hello ${'to'} you", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
Object o = expr.getValue();
|
||||
assertThat(o.toString()).isEqualTo("hello to you");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsingSimpleTemplateExpression03() throws Exception {
|
||||
void parsingSimpleTemplateExpression03() throws Exception {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expr = parser.parseExpression("The quick ${'brown'} fox jumped over the ${'lazy'} dog",
|
||||
DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
Object o = expr.getValue();
|
||||
assertThat(o.toString()).isEqualTo("The quick brown fox jumped over the lazy dog");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsingSimpleTemplateExpression04() throws Exception {
|
||||
void parsingSimpleTemplateExpression04() throws Exception {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression expr = parser.parseExpression("${'hello'} world", DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
Expression expr = parser.parseExpression("${'hello'} world", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
Object o = expr.getValue();
|
||||
assertThat(o.toString()).isEqualTo("hello world");
|
||||
|
||||
expr = parser.parseExpression("", DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
expr = parser.parseExpression("", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
o = expr.getValue();
|
||||
assertThat(o.toString()).isEqualTo("");
|
||||
|
||||
expr = parser.parseExpression("abc", DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
expr = parser.parseExpression("abc", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
o = expr.getValue();
|
||||
assertThat(o.toString()).isEqualTo("abc");
|
||||
|
||||
expr = parser.parseExpression("abc", DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
expr = parser.parseExpression("abc", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
o = expr.getValue((Object)null);
|
||||
assertThat(o.toString()).isEqualTo("abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCompositeStringExpression() throws Exception {
|
||||
void compositeStringExpression() throws Exception {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
Expression ex = parser.parseExpression("hello ${'world'}", DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
Expression ex = parser.parseExpression("hello ${'world'}", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
assertThat(ex.getValue()).isInstanceOf(String.class).isEqualTo("hello world");
|
||||
assertThat(ex.getValue(String.class)).isInstanceOf(String.class).isEqualTo("hello world");
|
||||
assertThat(ex.getValue((Object)null, String.class)).isInstanceOf(String.class).isEqualTo("hello world");
|
||||
@@ -154,15 +127,15 @@ public class TemplateExpressionParsingTests extends AbstractExpressionTests {
|
||||
static class Rooty {}
|
||||
|
||||
@Test
|
||||
public void testNestedExpressions() throws Exception {
|
||||
void nestedExpressions() throws Exception {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
// treat the nested ${..} as a part of the expression
|
||||
Expression ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
Expression ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} world",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
String s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertThat(s).isEqualTo("hello 4 world");
|
||||
|
||||
// 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);
|
||||
ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#root.listOfNumbersUpToTen.$[#this%2==1]==3]} world",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
assertThat(ex.getClass()).isEqualTo(CompositeStringExpression.class);
|
||||
CompositeStringExpression cse = (CompositeStringExpression)ex;
|
||||
Expression[] exprs = cse.getExpressions();
|
||||
@@ -171,60 +144,59 @@ public class TemplateExpressionParsingTests extends AbstractExpressionTests {
|
||||
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertThat(s).isEqualTo("hello world");
|
||||
|
||||
ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} ${listOfNumbersUpToTen.$[#this>5]} world",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
ex = parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} ${listOfNumbersUpToTen.$[#this>5]} world",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertThat(s).isEqualTo("hello 4 10 world");
|
||||
|
||||
assertThatExceptionOfType(ParseException.class).isThrownBy(() ->
|
||||
parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} ${listOfNumbersUpToTen.$[#this>5] world",DEFAULT_TEMPLATE_PARSER_CONTEXT))
|
||||
parser.parseExpression("hello ${listOfNumbersUpToTen.$[#this<5]} ${listOfNumbersUpToTen.$[#this>5] world",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT))
|
||||
.satisfies(pex -> assertThat(pex.getSimpleMessage()).isEqualTo("No ending suffix '}' for expression starting at character 41: ${listOfNumbersUpToTen.$[#this>5] world"));
|
||||
|
||||
assertThatExceptionOfType(ParseException.class).isThrownBy(() ->
|
||||
parser.parseExpression("hello ${listOfNumbersUpToTen.$[#root.listOfNumbersUpToTen.$[#this%2==1==3]} world",DEFAULT_TEMPLATE_PARSER_CONTEXT))
|
||||
parser.parseExpression("hello ${listOfNumbersUpToTen.$[#root.listOfNumbersUpToTen.$[#this%2==1==3]} world",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT))
|
||||
.satisfies(pex -> assertThat(pex.getSimpleMessage()).isEqualTo("Found closing '}' at position 74 but most recent opening is '[' at position 30"));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
public void testClashingWithSuffixes() throws Exception {
|
||||
void clashingWithSuffixes() 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);
|
||||
Expression ex = parser.parseExpression("hello ${3+4} world",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
String s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertThat(s).isEqualTo("hello 7 world");
|
||||
|
||||
ex = parser.parseExpression("hello ${3+4} wo${'${'}rld",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
ex = parser.parseExpression("hello ${3+4} wo${'${'}rld",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertThat(s).isEqualTo("hello 7 wo${rld");
|
||||
|
||||
ex = parser.parseExpression("hello ${3+4} wo}rld",DEFAULT_TEMPLATE_PARSER_CONTEXT);
|
||||
ex = parser.parseExpression("hello ${3+4} wo}rld",DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT);
|
||||
s = ex.getValue(TestScenarioCreator.getTestEvaluationContext(),String.class);
|
||||
assertThat(s).isEqualTo("hello 7 wo}rld");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParsingNormalExpressionThroughTemplateParser() throws Exception {
|
||||
void parsingNormalExpressionThroughTemplateParser() throws Exception {
|
||||
Expression expr = parser.parseExpression("1+2+3");
|
||||
assertThat(expr.getValue()).isEqualTo(6);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorCases() throws Exception {
|
||||
void errorCases() throws Exception {
|
||||
assertThatExceptionOfType(ParseException.class).isThrownBy(() ->
|
||||
parser.parseExpression("hello ${'world'", DEFAULT_TEMPLATE_PARSER_CONTEXT))
|
||||
parser.parseExpression("hello ${'world'", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT))
|
||||
.satisfies(pex -> {
|
||||
assertThat(pex.getSimpleMessage()).isEqualTo("No ending suffix '}' for expression starting at character 6: ${'world'");
|
||||
assertThat(pex.getExpressionString()).isEqualTo("hello ${'world'");
|
||||
});
|
||||
assertThatExceptionOfType(ParseException.class).isThrownBy(() ->
|
||||
parser.parseExpression("hello ${'wibble'${'world'}", DEFAULT_TEMPLATE_PARSER_CONTEXT))
|
||||
parser.parseExpression("hello ${'wibble'${'world'}", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT))
|
||||
.satisfies(pex -> assertThat(pex.getSimpleMessage()).isEqualTo("No ending suffix '}' for expression starting at character 6: ${'wibble'${'world'}"));
|
||||
assertThatExceptionOfType(ParseException.class).isThrownBy(() ->
|
||||
parser.parseExpression("hello ${} world", DEFAULT_TEMPLATE_PARSER_CONTEXT))
|
||||
parser.parseExpression("hello ${} world", DOLLAR_SIGN_TEMPLATE_PARSER_CONTEXT))
|
||||
.satisfies(pex -> assertThat(pex.getSimpleMessage()).isEqualTo("No expression defined within delimiter '${}' at character 6"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTemplateParserContext() {
|
||||
void templateParserContext() {
|
||||
TemplateParserContext tpc = new TemplateParserContext("abc","def");
|
||||
assertThat(tpc.getExpressionPrefix()).isEqualTo("abc");
|
||||
assertThat(tpc.getExpressionSuffix()).isEqualTo("def");
|
||||
|
||||
Reference in New Issue
Block a user