diff --git a/spring-expression/src/main/java/org/springframework/expression/ParserContext.java b/spring-expression/src/main/java/org/springframework/expression/ParserContext.java index 86f1b2ba6f..d8504f1a19 100644 --- a/spring-expression/src/main/java/org/springframework/expression/ParserContext.java +++ b/spring-expression/src/main/java/org/springframework/expression/ParserContext.java @@ -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. + *
A template consists of literal text that can be mixed with expressions. + * Some examples: *
- * Some literal text
+ * Some literal text
* Hello #{name.firstName}!
* #{3 + 4}
*
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java
index 2724408332..59e363e04d 100644
--- a/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/SpelReproTests.java
@@ -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());
diff --git a/spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java b/spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java
index b810aed4ab..ba3b9e67e9 100644
--- a/spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java
+++ b/spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java
@@ -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");