Merge branch '6.0.x'
This commit is contained in:
commit
ecc0a6d2db
|
@ -1479,7 +1479,7 @@ public abstract class ClassUtils {
|
|||
Assert.notNull(methodName, "Method name must not be null");
|
||||
try {
|
||||
Method method = clazz.getMethod(methodName, args);
|
||||
return Modifier.isStatic(method.getModifiers()) ? method : null;
|
||||
return (Modifier.isStatic(method.getModifiers()) ? method : null);
|
||||
}
|
||||
catch (NoSuchMethodException ex) {
|
||||
return null;
|
||||
|
|
|
@ -77,7 +77,6 @@ import org.springframework.expression.spel.ast.Ternary;
|
|||
import org.springframework.expression.spel.ast.TypeReference;
|
||||
import org.springframework.expression.spel.ast.VariableReference;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
|
@ -137,12 +136,13 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
this.tokenStreamPointer = 0;
|
||||
this.constructedNodes.clear();
|
||||
SpelNodeImpl ast = eatExpression();
|
||||
Assert.state(ast != null, "No node");
|
||||
if (ast == null) {
|
||||
throw new SpelParseException(this.expressionString, 0, SpelMessage.OOD);
|
||||
}
|
||||
Token t = peekToken();
|
||||
if (t != null) {
|
||||
throw new SpelParseException(t.startPos, SpelMessage.MORE_INPUT, toString(nextToken()));
|
||||
throw new SpelParseException(this.expressionString, t.startPos, SpelMessage.MORE_INPUT, toString(nextToken()));
|
||||
}
|
||||
Assert.isTrue(this.constructedNodes.isEmpty(), "At least one node expected");
|
||||
return new SpelExpression(expressionString, ast, this.configuration);
|
||||
}
|
||||
catch (InternalParseException ex) {
|
||||
|
@ -254,20 +254,20 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
if (tk == TokenKind.EQ) {
|
||||
return new OpEQ(t.startPos, t.endPos, expr, rhExpr);
|
||||
}
|
||||
Assert.isTrue(tk == TokenKind.NE, "Not-equals token expected");
|
||||
return new OpNE(t.startPos, t.endPos, expr, rhExpr);
|
||||
if (tk == TokenKind.NE) {
|
||||
return new OpNE(t.startPos, t.endPos, expr, rhExpr);
|
||||
}
|
||||
}
|
||||
|
||||
if (tk == TokenKind.INSTANCEOF) {
|
||||
return new OperatorInstanceof(t.startPos, t.endPos, expr, rhExpr);
|
||||
}
|
||||
|
||||
if (tk == TokenKind.MATCHES) {
|
||||
return new OperatorMatches(this.patternCache, t.startPos, t.endPos, expr, rhExpr);
|
||||
}
|
||||
|
||||
Assert.isTrue(tk == TokenKind.BETWEEN, "Between token expected");
|
||||
return new OperatorBetween(t.startPos, t.endPos, expr, rhExpr);
|
||||
if (tk == TokenKind.BETWEEN) {
|
||||
return new OperatorBetween(t.startPos, t.endPos, expr, rhExpr);
|
||||
}
|
||||
}
|
||||
return expr;
|
||||
}
|
||||
|
@ -304,8 +304,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
else if (t.kind == TokenKind.DIV) {
|
||||
expr = new OpDivide(t.startPos, t.endPos, expr, rhExpr);
|
||||
}
|
||||
else {
|
||||
Assert.isTrue(t.kind == TokenKind.MOD, "Mod token expected");
|
||||
else if (t.kind == TokenKind.MOD) {
|
||||
expr = new OpModulus(t.startPos, t.endPos, expr, rhExpr);
|
||||
}
|
||||
}
|
||||
|
@ -335,18 +334,21 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
// unaryExpression: (PLUS^ | MINUS^ | BANG^ | INC^ | DEC^) unaryExpression | primaryExpression ;
|
||||
@Nullable
|
||||
private SpelNodeImpl eatUnaryExpression() {
|
||||
if (peekToken(TokenKind.PLUS, TokenKind.MINUS, TokenKind.NOT)) {
|
||||
if (peekToken(TokenKind.NOT, TokenKind.PLUS, TokenKind.MINUS)) {
|
||||
Token t = takeToken();
|
||||
SpelNodeImpl expr = eatUnaryExpression();
|
||||
Assert.state(expr != null, "No node");
|
||||
if (expr == null) {
|
||||
throw internalException(t.startPos, SpelMessage.OOD);
|
||||
}
|
||||
if (t.kind == TokenKind.NOT) {
|
||||
return new OperatorNot(t.startPos, t.endPos, expr);
|
||||
}
|
||||
if (t.kind == TokenKind.PLUS) {
|
||||
return new OpPlus(t.startPos, t.endPos, expr);
|
||||
}
|
||||
Assert.isTrue(t.kind == TokenKind.MINUS, "Minus token expected");
|
||||
return new OpMinus(t.startPos, t.endPos, expr);
|
||||
if (t.kind == TokenKind.MINUS) {
|
||||
return new OpMinus(t.startPos, t.endPos, expr);
|
||||
}
|
||||
}
|
||||
if (peekToken(TokenKind.INC, TokenKind.DEC)) {
|
||||
Token t = takeToken();
|
||||
|
@ -354,7 +356,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
if (t.getKind() == TokenKind.INC) {
|
||||
return new OpInc(t.startPos, t.endPos, false, expr);
|
||||
}
|
||||
return new OpDec(t.startPos, t.endPos, false, expr);
|
||||
if (t.kind == TokenKind.DEC) {
|
||||
return new OpDec(t.startPos, t.endPos, false, expr);
|
||||
}
|
||||
}
|
||||
return eatPrimaryExpression();
|
||||
}
|
||||
|
@ -414,7 +418,6 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
return pop();
|
||||
}
|
||||
if (peekToken() == null) {
|
||||
// unexpectedly ran out of data
|
||||
throw internalException(t.startPos, SpelMessage.OOD);
|
||||
}
|
||||
else {
|
||||
|
@ -460,8 +463,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
|
||||
private void eatConstructorArgs(List<SpelNodeImpl> accumulatedArguments) {
|
||||
if (!peekToken(TokenKind.LPAREN)) {
|
||||
throw new InternalParseException(new SpelParseException(this.expressionString,
|
||||
positionOf(peekToken()), SpelMessage.MISSING_CONSTRUCTOR_ARGS));
|
||||
throw internalException(positionOf(peekToken()), SpelMessage.MISSING_CONSTRUCTOR_ARGS);
|
||||
}
|
||||
consumeArguments(accumulatedArguments);
|
||||
eatToken(TokenKind.RPAREN);
|
||||
|
@ -472,7 +474,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
*/
|
||||
private void consumeArguments(List<SpelNodeImpl> accumulatedArguments) {
|
||||
Token t = peekToken();
|
||||
Assert.state(t != null, "Expected token");
|
||||
if (t == null) {
|
||||
return;
|
||||
}
|
||||
int pos = t.startPos;
|
||||
Token next;
|
||||
do {
|
||||
|
@ -575,8 +579,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
private boolean maybeEatTypeReference() {
|
||||
if (peekToken(TokenKind.IDENTIFIER)) {
|
||||
Token typeName = peekToken();
|
||||
Assert.state(typeName != null, "Expected token");
|
||||
if (!"T".equals(typeName.stringValue())) {
|
||||
if (typeName == null || !"T".equals(typeName.stringValue())) {
|
||||
return false;
|
||||
}
|
||||
// It looks like a type reference but is T being used as a map key?
|
||||
|
@ -605,8 +608,7 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
private boolean maybeEatNullReference() {
|
||||
if (peekToken(TokenKind.IDENTIFIER)) {
|
||||
Token nullToken = peekToken();
|
||||
Assert.state(nullToken != null, "Expected token");
|
||||
if (!"null".equalsIgnoreCase(nullToken.stringValue())) {
|
||||
if (nullToken == null || !"null".equalsIgnoreCase(nullToken.stringValue())) {
|
||||
return false;
|
||||
}
|
||||
nextToken();
|
||||
|
@ -619,12 +621,13 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
//projection: PROJECT^ expression RCURLY!;
|
||||
private boolean maybeEatProjection(boolean nullSafeNavigation) {
|
||||
Token t = peekToken();
|
||||
if (!peekToken(TokenKind.PROJECT, true)) {
|
||||
if (t == null || !peekToken(TokenKind.PROJECT, true)) {
|
||||
return false;
|
||||
}
|
||||
Assert.state(t != null, "No token");
|
||||
SpelNodeImpl expr = eatExpression();
|
||||
Assert.state(expr != null, "No node");
|
||||
if (expr == null) {
|
||||
throw internalException(t.startPos, SpelMessage.OOD);
|
||||
}
|
||||
eatToken(TokenKind.RSQUARE);
|
||||
this.constructedNodes.push(new Projection(nullSafeNavigation, t.startPos, t.endPos, expr));
|
||||
return true;
|
||||
|
@ -634,15 +637,13 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
// map = LCURLY (key ':' value (COMMA key ':' value)*) RCURLY
|
||||
private boolean maybeEatInlineListOrMap() {
|
||||
Token t = peekToken();
|
||||
if (!peekToken(TokenKind.LCURLY, true)) {
|
||||
if (t == null || !peekToken(TokenKind.LCURLY, true)) {
|
||||
return false;
|
||||
}
|
||||
Assert.state(t != null, "No token");
|
||||
SpelNodeImpl expr = null;
|
||||
Token closingCurly = peekToken();
|
||||
if (peekToken(TokenKind.RCURLY, true)) {
|
||||
if (closingCurly != null && peekToken(TokenKind.RCURLY, true)) {
|
||||
// empty list '{}'
|
||||
Assert.state(closingCurly != null, "No token");
|
||||
expr = new InlineList(t.startPos, closingCurly.endPos);
|
||||
}
|
||||
else if (peekToken(TokenKind.COLON, true)) {
|
||||
|
@ -695,12 +696,13 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
|
||||
private boolean maybeEatIndexer() {
|
||||
Token t = peekToken();
|
||||
if (!peekToken(TokenKind.LSQUARE, true)) {
|
||||
if (t == null || !peekToken(TokenKind.LSQUARE, true)) {
|
||||
return false;
|
||||
}
|
||||
Assert.state(t != null, "No token");
|
||||
SpelNodeImpl expr = eatExpression();
|
||||
Assert.state(expr != null, "No node");
|
||||
if (expr == null) {
|
||||
throw internalException(t.startPos, SpelMessage.MISSING_SELECTION_EXPRESSION);
|
||||
}
|
||||
eatToken(TokenKind.RSQUARE);
|
||||
this.constructedNodes.push(new Indexer(t.startPos, t.endPos, expr));
|
||||
return true;
|
||||
|
@ -708,10 +710,9 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
|
||||
private boolean maybeEatSelection(boolean nullSafeNavigation) {
|
||||
Token t = peekToken();
|
||||
if (!peekSelectToken()) {
|
||||
if (t == null || !peekSelectToken()) {
|
||||
return false;
|
||||
}
|
||||
Assert.state(t != null, "No token");
|
||||
nextToken();
|
||||
SpelNodeImpl expr = eatExpression();
|
||||
if (expr == null) {
|
||||
|
@ -889,9 +890,14 @@ class InternalSpelExpressionParser extends TemplateAwareExpressionParser {
|
|||
//parenExpr : LPAREN! expression RPAREN!;
|
||||
private boolean maybeEatParenExpression() {
|
||||
if (peekToken(TokenKind.LPAREN)) {
|
||||
nextToken();
|
||||
Token t = nextToken();
|
||||
if (t == null) {
|
||||
return false;
|
||||
}
|
||||
SpelNodeImpl expr = eatExpression();
|
||||
Assert.state(expr != null, "No node");
|
||||
if (expr == null) {
|
||||
throw internalException(t.startPos, SpelMessage.OOD);
|
||||
}
|
||||
eatToken(TokenKind.RPAREN);
|
||||
push(expr);
|
||||
return true;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright 2002-2021 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.
|
||||
|
@ -65,7 +65,7 @@ class Token {
|
|||
|
||||
public boolean isNumericRelationalOperator() {
|
||||
return (this.kind == TokenKind.GT || this.kind == TokenKind.GE || this.kind == TokenKind.LT ||
|
||||
this.kind == TokenKind.LE || this.kind==TokenKind.EQ || this.kind==TokenKind.NE);
|
||||
this.kind == TokenKind.LE || this.kind == TokenKind.EQ || this.kind == TokenKind.NE);
|
||||
}
|
||||
|
||||
public String stringValue() {
|
||||
|
@ -87,14 +87,14 @@ class Token {
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder s = new StringBuilder();
|
||||
s.append('[').append(this.kind.toString());
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append('[').append(this.kind);
|
||||
if (this.kind.hasPayload()) {
|
||||
s.append(':').append(this.data);
|
||||
sb.append(':').append(this.data);
|
||||
}
|
||||
s.append(']');
|
||||
s.append('(').append(this.startPos).append(',').append(this.endPos).append(')');
|
||||
return s.toString();
|
||||
sb.append(']');
|
||||
sb.append('(').append(this.startPos).append(',').append(this.endPos).append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -39,7 +39,9 @@ import static org.springframework.expression.spel.SpelMessage.NON_TERMINATING_DO
|
|||
import static org.springframework.expression.spel.SpelMessage.NON_TERMINATING_QUOTED_STRING;
|
||||
import static org.springframework.expression.spel.SpelMessage.NOT_AN_INTEGER;
|
||||
import static org.springframework.expression.spel.SpelMessage.NOT_A_LONG;
|
||||
import static org.springframework.expression.spel.SpelMessage.OOD;
|
||||
import static org.springframework.expression.spel.SpelMessage.REAL_CANNOT_BE_LONG;
|
||||
import static org.springframework.expression.spel.SpelMessage.RIGHT_OPERAND_PROBLEM;
|
||||
import static org.springframework.expression.spel.SpelMessage.RUN_OUT_OF_ARGUMENTS;
|
||||
import static org.springframework.expression.spel.SpelMessage.UNEXPECTED_DATA_AFTER_DOT;
|
||||
import static org.springframework.expression.spel.SpelMessage.UNEXPECTED_ESCAPE_CHAR;
|
||||
|
@ -76,8 +78,8 @@ class SpelParserTests {
|
|||
|
||||
private static void assertNullOrEmptyExpressionIsRejected(ThrowingCallable throwingCallable) {
|
||||
assertThatIllegalArgumentException()
|
||||
.isThrownBy(throwingCallable)
|
||||
.withMessage("'expressionString' must not be null or blank");
|
||||
.isThrownBy(throwingCallable)
|
||||
.withMessage("'expressionString' must not be null or blank");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -152,7 +154,13 @@ class SpelParserTests {
|
|||
assertParseException(() -> parser.parseRaw("new String(3"), RUN_OUT_OF_ARGUMENTS, 10);
|
||||
assertParseException(() -> parser.parseRaw("new String("), RUN_OUT_OF_ARGUMENTS, 10);
|
||||
assertParseException(() -> parser.parseRaw("\"abc"), NON_TERMINATING_DOUBLE_QUOTED_STRING, 0);
|
||||
assertParseException(() -> parser.parseRaw("abc\""), NON_TERMINATING_DOUBLE_QUOTED_STRING, 3);
|
||||
assertParseException(() -> parser.parseRaw("'abc"), NON_TERMINATING_QUOTED_STRING, 0);
|
||||
assertParseException(() -> parser.parseRaw("abc'"), NON_TERMINATING_QUOTED_STRING, 3);
|
||||
assertParseException(() -> parser.parseRaw("("), OOD, 0);
|
||||
assertParseException(() -> parser.parseRaw(")"), OOD, 0);
|
||||
assertParseException(() -> parser.parseRaw("+"), OOD, 0);
|
||||
assertParseException(() -> parser.parseRaw("1+"), RIGHT_OPERAND_PROBLEM, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -377,7 +385,7 @@ class SpelParserTests {
|
|||
|
||||
private void checkNumberError(String expression, SpelMessage expectedMessage) {
|
||||
assertParseExceptionThrownBy(() -> parser.parseRaw(expression))
|
||||
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(expectedMessage));
|
||||
.satisfies(ex -> assertThat(ex.getMessageCode()).isEqualTo(expectedMessage));
|
||||
}
|
||||
|
||||
private static ThrowableAssertAlternative<SpelParseException> assertParseExceptionThrownBy(ThrowingCallable throwingCallable) {
|
||||
|
@ -386,15 +394,18 @@ class SpelParserTests {
|
|||
|
||||
private static void assertParseException(ThrowingCallable throwingCallable, SpelMessage expectedMessage, int expectedPosition) {
|
||||
assertParseExceptionThrownBy(throwingCallable)
|
||||
.satisfies(parseExceptionRequirements(expectedMessage, expectedPosition));
|
||||
.satisfies(parseExceptionRequirements(expectedMessage, expectedPosition));
|
||||
}
|
||||
|
||||
private static <E extends SpelParseException> Consumer<E> parseExceptionRequirements(
|
||||
SpelMessage expectedMessage, int expectedPosition) {
|
||||
|
||||
return ex -> {
|
||||
assertThat(ex.getMessageCode()).isEqualTo(expectedMessage);
|
||||
assertThat(ex.getPosition()).isEqualTo(expectedPosition);
|
||||
assertThat(ex.getMessage()).contains(ex.getExpressionString());
|
||||
if (ex.getExpressionString() != null) {
|
||||
assertThat(ex.getMessage()).contains(ex.getExpressionString());
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue