Skip to content

Commit bb3dc49

Browse files
committed
Introduce ParseException.
1 parent ae19ced commit bb3dc49

File tree

2 files changed

+38
-26
lines changed

2 files changed

+38
-26
lines changed

src/main/java/org/springframework/data/spel/DefaultValueExpressionParser.java

Lines changed: 27 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import java.util.ArrayList;
1919
import java.util.List;
2020

21+
import org.springframework.expression.ParseException;
2122
import org.springframework.expression.ParserContext;
2223
import org.springframework.util.Assert;
2324
import org.springframework.util.SystemPropertyUtils;
@@ -68,48 +69,50 @@ && findPlaceholderEndIndex(expressionString, expressionIndex) != expressionStrin
6869
return parseComposite(expressionString, placerholderIndex, expressionIndex);
6970
}
7071

71-
private CompositeValueExpression parseComposite(String expression, int placerholderIndex, int expressionIndex) {
72+
private CompositeValueExpression parseComposite(String expressionString, int placerholderIndex, int expressionIndex) {
7273

7374
List<ValueExpression> expressions = new ArrayList<>(PLACEHOLDER_PREFIX_LENGTH);
7475
int startIndex = getStartIndex(placerholderIndex, expressionIndex);
7576

7677
if (startIndex != 0) {
77-
expressions.add(new LiteralValueExpression(expression.substring(0, startIndex)));
78+
expressions.add(new LiteralValueExpression(expressionString.substring(0, startIndex)));
7879
}
7980

8081
while (startIndex != -1) {
8182

82-
int endIndex = findPlaceholderEndIndex(expression, startIndex);
83-
if (endIndex != -1) {
83+
int endIndex = findPlaceholderEndIndex(expressionString, startIndex);
8484

85-
int afterClosingParenthesisIndex = endIndex + 1;
86-
String part = expression.substring(startIndex, afterClosingParenthesisIndex);
85+
if (endIndex == -1) {
86+
throw new ParseException(expressionString, startIndex,
87+
"No ending suffix '}' for expression starting at character %d: %s".formatted(startIndex,
88+
expressionString.substring(startIndex)));
89+
}
8790

88-
if (part.startsWith(PLACEHOLDER_PREFIX)) {
89-
expressions.add(createPlaceholder(part));
90-
} else {
91-
expressions.add(createExpression(part));
92-
}
91+
int afterClosingParenthesisIndex = endIndex + 1;
92+
String part = expressionString.substring(startIndex, afterClosingParenthesisIndex);
93+
94+
if (part.startsWith(PLACEHOLDER_PREFIX)) {
95+
expressions.add(createPlaceholder(part));
96+
} else {
97+
expressions.add(createExpression(part));
98+
}
9399

94-
placerholderIndex = expression.indexOf(PLACEHOLDER_PREFIX, endIndex);
95-
expressionIndex = expression.indexOf(EXPRESSION_PREFIX, endIndex);
100+
placerholderIndex = expressionString.indexOf(PLACEHOLDER_PREFIX, endIndex);
101+
expressionIndex = expressionString.indexOf(EXPRESSION_PREFIX, endIndex);
96102

97-
startIndex = getStartIndex(placerholderIndex, expressionIndex);
103+
startIndex = getStartIndex(placerholderIndex, expressionIndex);
98104

99-
if (startIndex == -1) {
100-
// no next expression but we're capturing everything after the expression as literal.
101-
expressions.add(new LiteralValueExpression(expression.substring(afterClosingParenthesisIndex)));
102-
} else {
103-
// capture literal after the expression ends and before the next starts.
104-
expressions.add(new LiteralValueExpression(expression.substring(afterClosingParenthesisIndex, startIndex)));
105-
}
105+
if (startIndex == -1) {
106+
// no next expression but we're capturing everything after the expression as literal.
107+
expressions.add(new LiteralValueExpression(expressionString.substring(afterClosingParenthesisIndex)));
106108
} else {
107-
expressions.add(new LiteralValueExpression(expression.substring(startIndex)));
108-
startIndex = -1;
109+
// capture literal after the expression ends and before the next starts.
110+
expressions
111+
.add(new LiteralValueExpression(expressionString.substring(afterClosingParenthesisIndex, startIndex)));
109112
}
110113
}
111114

112-
return new CompositeValueExpression(expression, expressions);
115+
return new CompositeValueExpression(expressionString, expressions);
113116
}
114117

115118
private static int getStartIndex(int placerholderIndex, int expressionIndex) {

src/test/java/org/springframework/data/spel/ValueEvaluationUnitTests.java

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,6 @@ void shouldParseAndEvaluateExpressions() {
7171
assertThat(eval("${env.key.one}")).isEqualTo("value");
7272
assertThat(eval("${env.key.two}")).isEqualTo("42");
7373
assertThat(eval("${env.key.one")).isEqualTo("${env.key.one");
74-
assertThat(eval("#{'foo'}-${env.key.one")).isEqualTo("foo-${env.key.one");
7574
assertThat(eval("#{'foo'}-")).isEqualTo("foo-");
7675
assertThat(eval("#{'fo\"o'}-")).isEqualTo("fo\"o-");
7776
assertThat(eval("#{\"foo\"}-")).isEqualTo("foo-");
@@ -99,16 +98,26 @@ void shouldParseLiteral() {
9998
@Test // GH-2369
10099
void shouldParseCompoundExpression() {
101100

102-
assertThat(eval("#{'foo'}-${key.one")).isEqualTo("foo-${key.one");
103101
assertThat(eval("#{'foo'}-")).isEqualTo("foo-");
104102
assertThat(eval("#{'fo\"o'}-")).isEqualTo("fo\"o-");
105103
assertThat(eval("#{\"foo\"}-")).isEqualTo("foo-");
106104
assertThat(eval("#{\"fo'o\"}-")).isEqualTo("fo'o-");
107105
assertThat(eval("${env.key.one}-")).isEqualTo("value-");
108106
assertThat(eval("${env.key.one}-and-some-#{'foo'}-#{#contextVar}")).isEqualTo("value-and-some-foo-contextVal");
107+
}
108+
109+
@Test // GH-2369
110+
void shouldRaiseParseException() {
111+
112+
assertThatExceptionOfType(ParseException.class).isThrownBy(() -> eval("#{'foo'}-${key.one")).withMessageContaining(
113+
"Expression [#{'foo'}-${key.one] @9: No ending suffix '}' for expression starting at character 9: ${key.one");
114+
115+
assertThatExceptionOfType(ParseException.class).isThrownBy(() -> eval("#{'foo'}-${env.key.one"));
116+
assertThatExceptionOfType(ParseException.class).isThrownBy(() -> eval("#{'foo'"));
109117

110118
assertThatExceptionOfType(ParseException.class).isThrownBy(() -> eval("#{#foo - ${numeric.key}}"))
111119
.withMessageContaining("[#foo - ${numeric.key}]");
120+
112121
}
113122

114123
@Test // GH-2369

0 commit comments

Comments
 (0)