Skip to content

Commit 964950a

Browse files
committed
Reject null and empty SpEL expressions
Prior to gh-30325, supplying a null reference for a SpEL expression was effectively equivalent to supplying the String "null" as the expression. Consequently, evaluation of a null reference expression always evaluated to a null reference. However, that was accidental rather than by design. Due to the introduction of the checkExpressionLength(String) method in InternalSpelExpressionParser (in conjunction with gh-30325), an attempt to evaluate a null reference as a SpEL expression now results in a NullPointerException. To address both of these issues, TemplateAwareExpressionParser.parseExpression() and SpelExpressionParser.parseRaw() now reject null and empty SpEL expressions. See gh-30371 Closes gh-30373
1 parent 5afd94f commit 964950a

File tree

4 files changed

+43
-2
lines changed

4 files changed

+43
-2
lines changed

Diff for: spring-expression/src/main/java/org/springframework/expression/common/TemplateAwareExpressionParser.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2018 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@
2626
import org.springframework.expression.ParseException;
2727
import org.springframework.expression.ParserContext;
2828
import org.springframework.lang.Nullable;
29+
import org.springframework.util.Assert;
2930

3031
/**
3132
* An expression parser that understands templates. It can be subclassed by expression
@@ -34,6 +35,7 @@
3435
* @author Keith Donald
3536
* @author Juergen Hoeller
3637
* @author Andy Clement
38+
* @author Sam Brannen
3739
* @since 3.0
3840
*/
3941
public abstract class TemplateAwareExpressionParser implements ExpressionParser {
@@ -46,9 +48,11 @@ public Expression parseExpression(String expressionString) throws ParseException
4648
@Override
4749
public Expression parseExpression(String expressionString, @Nullable ParserContext context) throws ParseException {
4850
if (context != null && context.isTemplate()) {
51+
Assert.notNull(expressionString, "'expressionString' must not be null");
4952
return parseTemplate(expressionString, context);
5053
}
5154
else {
55+
Assert.hasText(expressionString, "'expressionString' must not be null or blank");
5256
return doParseExpression(expressionString, context);
5357
}
5458
}

Diff for: spring-expression/src/main/java/org/springframework/expression/spel/standard/SpelExpressionParser.java

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2014 the original author or authors.
2+
* Copyright 2002-2023 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,6 +28,7 @@
2828
*
2929
* @author Andy Clement
3030
* @author Juergen Hoeller
31+
* @author Sam Brannen
3132
* @since 3.0
3233
*/
3334
public class SpelExpressionParser extends TemplateAwareExpressionParser {
@@ -53,6 +54,7 @@ public SpelExpressionParser(SpelParserConfiguration configuration) {
5354

5455

5556
public SpelExpression parseRaw(String expressionString) throws ParseException {
57+
Assert.hasText(expressionString, "'expressionString' must not be null or blank");
5658
return doParseExpression(expressionString, null);
5759
}
5860

Diff for: spring-expression/src/test/java/org/springframework/expression/spel/TemplateExpressionParsingTests.java

+8
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030

3131
import static org.assertj.core.api.Assertions.assertThat;
3232
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
33+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
3334

3435
/**
3536
* @author Andy Clement
@@ -72,6 +73,13 @@ public boolean isTemplate() {
7273
private final SpelExpressionParser parser = new SpelExpressionParser();
7374

7475

76+
@Test
77+
void nullTemplateExpressionIsRejected() {
78+
assertThatIllegalArgumentException()
79+
.isThrownBy(() -> parser.parseExpression(null, DEFAULT_TEMPLATE_PARSER_CONTEXT))
80+
.withMessage("'expressionString' must not be null");
81+
}
82+
7583
@Test
7684
void parsingSimpleTemplateExpression01() {
7785
Expression expr = parser.parseExpression("hello ${'world'}", DEFAULT_TEMPLATE_PARSER_CONTEXT);

Diff for: spring-expression/src/test/java/org/springframework/expression/spel/standard/SpelParserTests.java

+27
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
import static org.assertj.core.api.Assertions.assertThat;
3535
import static org.assertj.core.api.Assertions.assertThatExceptionOfType;
36+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
3637
import static org.springframework.expression.spel.SpelMessage.MISSING_CONSTRUCTOR_ARGS;
3738
import static org.springframework.expression.spel.SpelMessage.NON_TERMINATING_DOUBLE_QUOTED_STRING;
3839
import static org.springframework.expression.spel.SpelMessage.NON_TERMINATING_QUOTED_STRING;
@@ -53,6 +54,32 @@ class SpelParserTests {
5354
private final SpelExpressionParser parser = new SpelExpressionParser();
5455

5556

57+
@Test
58+
void nullExpressionIsRejected() {
59+
assertNullOrEmptyExpressionIsRejected(() -> parser.parseExpression(null));
60+
assertNullOrEmptyExpressionIsRejected(() -> parser.parseRaw(null));
61+
}
62+
63+
@Test
64+
void emptyExpressionIsRejected() {
65+
assertNullOrEmptyExpressionIsRejected(() -> parser.parseExpression(""));
66+
assertNullOrEmptyExpressionIsRejected(() -> parser.parseRaw(""));
67+
}
68+
69+
@Test
70+
void blankExpressionIsRejected() {
71+
assertNullOrEmptyExpressionIsRejected(() -> parser.parseExpression(" "));
72+
assertNullOrEmptyExpressionIsRejected(() -> parser.parseExpression("\t\n"));
73+
assertNullOrEmptyExpressionIsRejected(() -> parser.parseRaw(" "));
74+
assertNullOrEmptyExpressionIsRejected(() -> parser.parseRaw("\t\n"));
75+
}
76+
77+
private static void assertNullOrEmptyExpressionIsRejected(ThrowingCallable throwingCallable) {
78+
assertThatIllegalArgumentException()
79+
.isThrownBy(throwingCallable)
80+
.withMessage("'expressionString' must not be null or blank");
81+
}
82+
5683
@Test
5784
void theMostBasic() {
5885
SpelExpression expr = parser.parseRaw("2");

0 commit comments

Comments
 (0)