diff --git a/spring-core/src/main/java/org/springframework/util/ObjectUtils.java b/spring-core/src/main/java/org/springframework/util/ObjectUtils.java index c2443857c3f..e9cbd603399 100644 --- a/spring-core/src/main/java/org/springframework/util/ObjectUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ObjectUtils.java @@ -16,18 +16,26 @@ package org.springframework.util; +import java.io.File; import java.lang.reflect.Array; +import java.net.InetAddress; import java.net.URI; import java.net.URL; +import java.nio.charset.Charset; +import java.nio.file.Path; +import java.time.ZoneId; import java.time.temporal.Temporal; import java.util.Arrays; import java.util.Collection; +import java.util.Currency; import java.util.Date; import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.StringJoiner; +import java.util.TimeZone; import java.util.UUID; +import java.util.regex.Pattern; import org.springframework.lang.Nullable; @@ -923,19 +931,27 @@ public abstract class ObjectUtils { *
Returns: *
In the context of this method, a simple value type is any of the following: - * a primitive wrapper (excluding {@code Void}), an {@code Enum}, a {@code Number}, - * a {@code Date}, a {@code Temporal}, a {@code UUID}, a {@code URI}, a {@code URL}, - * or a {@code Locale}. + * primitive wrapper (excluding {@link Void}), {@link Enum}, {@link Number}, + * {@link Date}, {@link Temporal}, {@link File}, {@link Path}, {@link URI}, + * {@link URL}, {@link InetAddress}, {@link Currency}, {@link Locale}, + * {@link UUID}, {@link Pattern}. * @param obj the object to build a string representation for * @return a concise string representation of the supplied object * @since 5.3.27 @@ -946,9 +962,23 @@ public abstract class ObjectUtils { if (obj == null) { return "null"; } + if (obj instanceof Optional>) { + Optional> optional = (Optional>) obj; + return (!optional.isPresent() ? "Optional.empty" : + String.format("Optional[%s]", nullSafeConciseToString(optional.get()))); + } if (obj instanceof Class>) { return ((Class>) obj).getName(); } + if (obj instanceof Charset) { + return ((Charset) obj).name(); + } + if (obj instanceof TimeZone) { + return ((TimeZone) obj).getID(); + } + if (obj instanceof ZoneId) { + return ((ZoneId) obj).getId(); + } if (obj instanceof CharSequence) { return StringUtils.truncate((CharSequence) obj); } @@ -964,7 +994,10 @@ public abstract class ObjectUtils { /** * Derived from {@link org.springframework.beans.BeanUtils#isSimpleValueType}. - * As of 5.3.28, considering {@code UUID} in addition to the bean-level check. + *
As of 5.3.28, considering {@link UUID} in addition to the bean-level check. + *
As of 5.3.29, additionally considering {@link File}, {@link Path},
+ * {@link InetAddress}, {@link Charset}, {@link Currency}, {@link TimeZone},
+ * {@link ZoneId}, {@link Pattern}.
*/
private static boolean isSimpleValueType(Class> type) {
return (Void.class != type && void.class != type &&
@@ -974,10 +1007,18 @@ public abstract class ObjectUtils {
Number.class.isAssignableFrom(type) ||
Date.class.isAssignableFrom(type) ||
Temporal.class.isAssignableFrom(type) ||
- UUID.class == type ||
+ ZoneId.class.isAssignableFrom(type) ||
+ TimeZone.class.isAssignableFrom(type) ||
+ File.class.isAssignableFrom(type) ||
+ Path.class.isAssignableFrom(type) ||
+ Charset.class.isAssignableFrom(type) ||
+ Currency.class.isAssignableFrom(type) ||
+ InetAddress.class.isAssignableFrom(type) ||
URI.class == type ||
URL.class == type ||
+ UUID.class == type ||
Locale.class == type ||
+ Pattern.class == type ||
Class.class == type));
}
diff --git a/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java b/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java
index 4fe1a257e4e..f3c8e8c353b 100644
--- a/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java
+++ b/spring-core/src/test/java/org/springframework/util/ObjectUtilsTests.java
@@ -16,23 +16,34 @@
package org.springframework.util;
+import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.BigInteger;
+import java.net.InetAddress;
import java.net.URI;
import java.net.URL;
+import java.net.UnknownHostException;
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Paths;
import java.sql.SQLException;
import java.time.LocalDate;
+import java.time.ZoneId;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Currency;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
+import java.util.Optional;
import java.util.Set;
+import java.util.TimeZone;
import java.util.UUID;
+import java.util.regex.Pattern;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
@@ -851,6 +862,41 @@ class ObjectUtilsTests {
assertThat(ObjectUtils.nullSafeConciseToString(null)).isEqualTo("null");
}
+ @Test
+ void nullSafeConciseToStringForEmptyOptional() {
+ Optional