Skip to content

Commit 8161316

Browse files
committed
Introduce StringUtils.truncate()
StringUtils.truncate() serves as central, consistent way for truncating strings used in log messages and exception failure messages, for immediate use in LogFormatUtils and ObjectUtils. See gh-30286 Closes gh-30290
1 parent 1734dec commit 8161316

File tree

3 files changed

+67
-2
lines changed

3 files changed

+67
-2
lines changed

spring-core/src/main/java/org/springframework/core/log/LogFormatUtils.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2021 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.
@@ -23,6 +23,7 @@
2323

2424
import org.springframework.lang.Nullable;
2525
import org.springframework.util.ObjectUtils;
26+
import org.springframework.util.StringUtils;
2627

2728
/**
2829
* Utility methods for formatting and logging messages.
@@ -78,7 +79,7 @@ public static String formatValue(
7879
result = ObjectUtils.nullSafeToString(ex);
7980
}
8081
if (maxLength != -1) {
81-
result = (result.length() > maxLength ? result.substring(0, maxLength) + " (truncated)..." : result);
82+
result = StringUtils.truncate(result, maxLength);
8283
}
8384
if (replaceNewlinesAndControlCharacters) {
8485
result = NEWLINE_PATTERN.matcher(result).replaceAll("<EOL>");

spring-core/src/main/java/org/springframework/util/StringUtils.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ public abstract class StringUtils {
7676

7777
private static final char EXTENSION_SEPARATOR = '.';
7878

79+
private static final int DEFAULT_TRUNCATION_THRESHOLD = 100;
80+
81+
private static final String TRUNCATION_SUFFIX = " (truncated)...";
82+
7983

8084
//---------------------------------------------------------------------
8185
// General convenience methods for working with Strings
@@ -1347,4 +1351,40 @@ public static String arrayToCommaDelimitedString(@Nullable Object[] arr) {
13471351
return arrayToDelimitedString(arr, ",");
13481352
}
13491353

1354+
/**
1355+
* Truncate the supplied {@link CharSequence}.
1356+
* <p>Delegates to {@link #truncate(CharSequence, int)}, supplying {@code 100}
1357+
* as the threshold.
1358+
* @param charSequence the {@code CharSequence} to truncate
1359+
* @return a truncated string, or a string representation of the original
1360+
* {@code CharSequence} if its length does not exceed the threshold
1361+
* @since 5.3.27
1362+
*/
1363+
public static String truncate(CharSequence charSequence) {
1364+
return truncate(charSequence, DEFAULT_TRUNCATION_THRESHOLD);
1365+
}
1366+
1367+
/**
1368+
* Truncate the supplied {@link CharSequence}.
1369+
* <p>If the length of the {@code CharSequence} is greater than the threshold,
1370+
* this method returns a {@linkplain CharSequence#subSequence(int, int)
1371+
* subsequence} of the {@code CharSequence} (up to the threshold) appended
1372+
* with the suffix {@code " (truncated)..."}. Otherwise, this method returns
1373+
* {@code charSequence.toString()}.
1374+
* @param charSequence the {@code CharSequence} to truncate
1375+
* @param threshold the maximum length after which to truncate; must be a
1376+
* positive number
1377+
* @return a truncated string, or a string representation of the original
1378+
* {@code CharSequence} if its length does not exceed the threshold
1379+
* @since 5.3.27
1380+
*/
1381+
public static String truncate(CharSequence charSequence, int threshold) {
1382+
Assert.isTrue(threshold > 0,
1383+
() -> "Truncation threshold must be a positive number: " + threshold);
1384+
if (charSequence.length() > threshold) {
1385+
return charSequence.subSequence(0, threshold) + TRUNCATION_SUFFIX;
1386+
}
1387+
return charSequence.toString();
1388+
}
1389+
13501390
}

spring-core/src/test/java/org/springframework/util/StringUtilsTests.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
import java.util.Properties;
2323

2424
import org.junit.jupiter.api.Test;
25+
import org.junit.jupiter.params.ParameterizedTest;
26+
import org.junit.jupiter.params.provider.CsvSource;
2527

2628
import static org.assertj.core.api.Assertions.assertThat;
2729
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
@@ -757,4 +759,26 @@ void collectionToDelimitedStringWithNullValuesShouldNotFail() {
757759
assertThat(StringUtils.collectionToCommaDelimitedString(Collections.singletonList(null))).isEqualTo("null");
758760
}
759761

762+
@Test
763+
void truncatePreconditions() {
764+
assertThatIllegalArgumentException()
765+
.isThrownBy(() -> StringUtils.truncate("foo", 0))
766+
.withMessage("Truncation threshold must be a positive number: 0");
767+
assertThatIllegalArgumentException()
768+
.isThrownBy(() -> StringUtils.truncate("foo", -99))
769+
.withMessage("Truncation threshold must be a positive number: -99");
770+
}
771+
772+
@ParameterizedTest
773+
@CsvSource(delimiterString = "-->", textBlock = """
774+
aardvark --> aardvark
775+
aardvark12 --> aardvark12
776+
aardvark123 --> aardvark12 (truncated)...
777+
aardvark, bird, cat --> aardvark, (truncated)...
778+
"""
779+
)
780+
void truncate(String text, String truncated) {
781+
assertThat(StringUtils.truncate(text, 10)).isEqualTo(truncated);
782+
}
783+
760784
}

0 commit comments

Comments
 (0)