Skip to content

Commit 5529294

Browse files
committed
Improve diagnostics in SpEL for repeated text
Attempting to create repeated text in a SpEL expression using the repeat operator can result in errors that are not very helpful to the user. This commit improves the diagnostics in SpEL for the repeat operator by throwing a SpelEvaluationException with a meaningful error message in order to better assist the user. Closes gh-30142
1 parent 935c29e commit 5529294

File tree

3 files changed

+41
-10
lines changed

3 files changed

+41
-10
lines changed

spring-expression/src/main/java/org/springframework/expression/spel/SpelMessage.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 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.
@@ -264,7 +264,11 @@ public enum SpelMessage {
264264

265265
/** @since 5.3.17 */
266266
MAX_ARRAY_ELEMENTS_THRESHOLD_EXCEEDED(Kind.ERROR, 1075,
267-
"Array declares too many elements, exceeding the threshold of ''{0}''");
267+
"Array declares too many elements, exceeding the threshold of ''{0}''"),
268+
269+
/** @since 5.3.26 */
270+
MAX_REPEATED_TEXT_SIZE_EXCEEDED(Kind.ERROR, 1076,
271+
"Repeated text results in too many characters, exceeding the threshold of ''{0}''");
268272

269273

270274
private final Kind kind;

spring-expression/src/main/java/org/springframework/expression/spel/ast/OpMultiply.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2022 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.
@@ -25,6 +25,8 @@
2525
import org.springframework.expression.TypedValue;
2626
import org.springframework.expression.spel.CodeFlow;
2727
import org.springframework.expression.spel.ExpressionState;
28+
import org.springframework.expression.spel.SpelEvaluationException;
29+
import org.springframework.expression.spel.SpelMessage;
2830
import org.springframework.util.Assert;
2931
import org.springframework.util.NumberUtils;
3032

@@ -52,6 +54,13 @@
5254
*/
5355
public class OpMultiply extends Operator {
5456

57+
/**
58+
* Maximum number of characters permitted in repeated text.
59+
* @since 5.3.26
60+
*/
61+
private static final int MAX_REPEATED_TEXT_SIZE = 256;
62+
63+
5564
public OpMultiply(int startPos, int endPos, SpelNodeImpl... operands) {
5665
super("*", startPos, endPos, operands);
5766
}
@@ -105,13 +114,21 @@ else if (CodeFlow.isIntegerForNumericOp(leftNumber) || CodeFlow.isIntegerForNume
105114
}
106115
}
107116

108-
if (leftOperand instanceof String text && rightOperand instanceof Integer repeats) {
109-
return new TypedValue(text.repeat(repeats));
117+
if (leftOperand instanceof String text && rightOperand instanceof Integer count) {
118+
checkRepeatedTextSize(text, count);
119+
return new TypedValue(text.repeat(count));
110120
}
111121

112122
return state.operate(Operation.MULTIPLY, leftOperand, rightOperand);
113123
}
114124

125+
private void checkRepeatedTextSize(String text, int count) {
126+
if (text.length() * count > MAX_REPEATED_TEXT_SIZE) {
127+
throw new SpelEvaluationException(getStartPosition(),
128+
SpelMessage.MAX_REPEATED_TEXT_SIZE_EXCEEDED, MAX_REPEATED_TEXT_SIZE);
129+
}
130+
}
131+
115132
@Override
116133
public boolean isCompilable() {
117134
if (!getLeftOperand().isCompilable()) {

spring-expression/src/test/java/org/springframework/expression/spel/OperatorTests.java

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121

2222
import org.junit.jupiter.api.Test;
2323

24+
import org.springframework.expression.Expression;
2425
import org.springframework.expression.spel.ast.Operator;
2526
import org.springframework.expression.spel.standard.SpelExpression;
2627

2728
import static org.assertj.core.api.Assertions.assertThat;
29+
import static org.springframework.expression.spel.SpelMessage.MAX_REPEATED_TEXT_SIZE_EXCEEDED;
2830

2931
/**
3032
* Tests the evaluation of expressions using various operators.
@@ -326,11 +328,6 @@ void realLiteral() {
326328
evaluate("3.5", 3.5d, Double.class);
327329
}
328330

329-
@Test
330-
void multiplyStringInt() {
331-
evaluate("'a' * 5", "aaaaa", String.class);
332-
}
333-
334331
@Test
335332
void multiplyDoubleDoubleGivesDouble() {
336333
evaluate("3.0d * 5.0d", 15.0d, Double.class);
@@ -578,6 +575,19 @@ void strings() {
578575
evaluate("'abc' != 'def'", true, Boolean.class);
579576
}
580577

578+
@Test
579+
void stringRepeat() {
580+
evaluate("'abc' * 0", "", String.class);
581+
evaluate("'abc' * 1", "abc", String.class);
582+
evaluate("'abc' * 2", "abcabc", String.class);
583+
584+
Expression expr = parser.parseExpression("'a' * 256");
585+
assertThat(expr.getValue(context, String.class)).hasSize(256);
586+
587+
// 4 is the position of the '*' (repeat operator)
588+
evaluateAndCheckError("'a' * 257", String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 4);
589+
}
590+
581591
@Test
582592
void longs() {
583593
evaluate("3L == 4L", false, Boolean.class);

0 commit comments

Comments
 (0)