Improve additional error messages in SpEL

This commit picks up where 987d6cca6d left off.

See gh-36756
This commit is contained in:
Sam Brannen
2026-05-11 11:28:44 +02:00
committed by Brian Clozel
parent ec89834fa8
commit 519d7332eb
3 changed files with 28 additions and 13 deletions
@@ -127,9 +127,9 @@ public class OpMultiply extends Operator {
throw new SpelEvaluationException(getStartPosition(),
SpelMessage.NEGATIVE_REPEATED_TEXT_COUNT, count);
}
int result = text.length() * count;
long result = (long) text.length() * (long) count;
if (result < 0 || result > MAX_REPEATED_TEXT_SIZE) {
throw new SpelEvaluationException(getStartPosition(),
throw new SpelEvaluationException(getRightOperand().getStartPosition(),
SpelMessage.MAX_REPEATED_TEXT_SIZE_EXCEEDED, MAX_REPEATED_TEXT_SIZE);
}
}
@@ -153,16 +153,19 @@ public class OpPlus extends Operator {
}
private void checkStringLength(String string) {
if (string.length() > MAX_CONCATENATED_STRING_LENGTH) {
checkStringLength(string.length());
}
private void checkStringLength(int stringLength) {
if (stringLength > MAX_CONCATENATED_STRING_LENGTH) {
throw new SpelEvaluationException(getStartPosition(),
SpelMessage.MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, MAX_CONCATENATED_STRING_LENGTH);
}
}
private TypedValue concatenate(String leftString, String rightString) {
String result = leftString + rightString;
checkStringLength(result);
return new TypedValue(result);
checkStringLength(leftString.length() + rightString.length());
return new TypedValue(leftString + rightString);
}
@Override
@@ -574,21 +574,26 @@ class OperatorTests extends AbstractExpressionTests {
@Test
void stringRepeat() {
evaluate("'abc' * 0", "", String.class);
evaluate("'abc' * 1", "abc", String.class);
evaluate("'abc' * 2", "abcabc", String.class);
String EMPTY = "";
evaluate("'' * 0", EMPTY, String.class);
evaluate("'' * 2", EMPTY, String.class);
evaluate("'abc' * 0", EMPTY, String.class);
evaluate("'Abc' * 1", "Abc", String.class);
evaluate("'Abc' * 2", "AbcAbc", String.class);
evaluate("'Abc' * 3", "AbcAbcAbc", String.class);
Expression expr = parser.parseExpression("'a' * 256");
assertThat(expr.getValue(context, String.class)).hasSize(256);
// 4 is the position of the '*' (repeat operator)
evaluateAndCheckError("'a' * 257", String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 4);
// 6 is the position of the repeatCount
evaluateAndCheckError("'a' * 257", String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 6);
// Integer overflow: 2 * ((Integer.MAX_VALUE / 2) + 1) --> integer overflow
int repeatCount = (Integer.MAX_VALUE / 2) + 1;
assertThat(2 * repeatCount).isNegative();
// 5 is the position of the '*' (repeat operator)
evaluateAndCheckError("'ab' * " + repeatCount, String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 5);
// 7 is the position of the repeatCount
evaluateAndCheckError("'ab' * " + repeatCount, String.class, MAX_REPEATED_TEXT_SIZE_EXCEEDED, 7);
}
@Test
@@ -623,12 +628,19 @@ class OperatorTests extends AbstractExpressionTests {
assertThat(expr.getValue(context, String.class)).hasSize(maxSize);
// Text is too big
context.setVariable("text1", createString(maxSize));
context.setVariable("text2", createString(maxSize));
evaluateAndCheckError("#text1 + #text2", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7);
context.setVariable("text1", createString(maxSize + 1));
evaluateAndCheckError("#text1 + ''", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7);
evaluateAndCheckError("#text1 + true", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7);
evaluateAndCheckError("'' + #text1", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 3);
evaluateAndCheckError("true + #text1", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 5);
context.setVariable("text1", createString(maxSize - 1));
evaluateAndCheckError("#text1 + 'YZ'", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7);
context.setVariable("text1", createString(maxSize / 2));
context.setVariable("text2", createString((maxSize / 2) + 1));
evaluateAndCheckError("#text1 + #text2", String.class, MAX_CONCATENATED_STRING_LENGTH_EXCEEDED, 7);