From ca4de8f19172306c91e04c0a73c8ae466c802cfe Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Wed, 14 Jun 2023 09:37:39 +0200 Subject: [PATCH] Consistent simple value type check Includes UUID treatment for data binding and bean dependency checks. Closes gh-30664 --- .../org/springframework/beans/BeanUtils.java | 27 +++++---------- .../springframework/beans/BeanUtilsTests.java | 8 +++-- .../org/springframework/util/ClassUtils.java | 34 +++++++++++++++++++ .../org/springframework/util/ObjectUtils.java | 27 ++------------- 4 files changed, 49 insertions(+), 47 deletions(-) diff --git a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java index 62676e04cd0d..8bde97f9a861 100644 --- a/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java +++ b/spring-beans/src/main/java/org/springframework/beans/BeanUtils.java @@ -23,15 +23,10 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; -import java.net.URI; -import java.net.URL; -import java.time.temporal.Temporal; import java.util.Arrays; import java.util.Collections; -import java.util.Date; import java.util.HashSet; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; @@ -663,26 +658,20 @@ public static boolean isSimpleProperty(Class type) { } /** - * Check if the given type represents a "simple" value type: a primitive or - * primitive wrapper, an enum, a String or other CharSequence, a Number, a - * Date, a Temporal, a URI, a URL, a Locale, or a Class. + * Check if the given type represents a "simple" value type for + * bean property and data binding purposes: + * a primitive or primitive wrapper, an {@code Enum}, a {@code String} + * or other {@code CharSequence}, a {@code Number}, a {@code Date}, + * a {@code Temporal}, a {@code UUID}, a {@code URI}, a {@code URL}, + * a {@code Locale}, or a {@code Class}. *

{@code Void} and {@code void} are not considered simple value types. * @param type the type to check * @return whether the given type represents a "simple" value type * @see #isSimpleProperty(Class) + * @see ClassUtils#isSimpleValueType(Class) */ public static boolean isSimpleValueType(Class type) { - return (Void.class != type && void.class != type && - (ClassUtils.isPrimitiveOrWrapper(type) || - Enum.class.isAssignableFrom(type) || - CharSequence.class.isAssignableFrom(type) || - Number.class.isAssignableFrom(type) || - Date.class.isAssignableFrom(type) || - Temporal.class.isAssignableFrom(type) || - URI.class == type || - URL.class == type || - Locale.class == type || - Class.class == type)); + return ClassUtils.isSimpleValueType(type); } diff --git a/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java b/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java index 0d75f7c37187..f10004a30fba 100644 --- a/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/BeanUtilsTests.java @@ -31,6 +31,7 @@ import java.util.Date; import java.util.List; import java.util.Locale; +import java.util.UUID; import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; @@ -470,7 +471,8 @@ void spr6063() { @ValueSource(classes = { boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, - DayOfWeek.class, String.class, LocalDateTime.class, Date.class, URI.class, URL.class, Locale.class, Class.class + DayOfWeek.class, String.class, LocalDateTime.class, Date.class, UUID.class, URI.class, URL.class, + Locale.class, Class.class }) void isSimpleValueType(Class type) { assertThat(BeanUtils.isSimpleValueType(type)).as("Type [" + type.getName() + "] should be a simple value type").isTrue(); @@ -486,8 +488,8 @@ void isNotSimpleValueType(Class type) { @ValueSource(classes = { boolean.class, char.class, byte.class, short.class, int.class, long.class, float.class, double.class, Boolean.class, Character.class, Byte.class, Short.class, Integer.class, Long.class, Float.class, Double.class, - DayOfWeek.class, String.class, LocalDateTime.class, Date.class, URI.class, URL.class, Locale.class, Class.class, - boolean[].class, Boolean[].class, LocalDateTime[].class, Date[].class + DayOfWeek.class, String.class, LocalDateTime.class, Date.class, UUID.class, URI.class, URL.class, + Locale.class, Class.class, boolean[].class, Boolean[].class, LocalDateTime[].class, Date[].class }) void isSimpleProperty(Class type) { assertThat(BeanUtils.isSimpleProperty(type)).as("Type [" + type.getName() + "] should be a simple property").isTrue(); diff --git a/spring-core/src/main/java/org/springframework/util/ClassUtils.java b/spring-core/src/main/java/org/springframework/util/ClassUtils.java index beba82d1702d..c555f8087233 100644 --- a/spring-core/src/main/java/org/springframework/util/ClassUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ClassUtils.java @@ -24,9 +24,13 @@ import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.lang.reflect.Proxy; +import java.net.URI; +import java.net.URL; +import java.time.temporal.Temporal; import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.Date; import java.util.Enumeration; import java.util.HashMap; import java.util.HashSet; @@ -34,10 +38,12 @@ import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; +import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.Set; import java.util.StringJoiner; +import java.util.UUID; import org.springframework.lang.Nullable; @@ -528,6 +534,34 @@ public static Class resolvePrimitiveIfNecessary(Class clazz) { return (clazz.isPrimitive() && clazz != void.class ? primitiveTypeToWrapperMap.get(clazz) : clazz); } + /** + * Delegate for {@link org.springframework.beans.BeanUtils#isSimpleValueType}. + * Also used by {@link ObjectUtils#nullSafeConciseToString}. + *

Check if the given type represents a common "simple" value type: + * a primitive or primitive wrapper, an {@code Enum}, a {@code String} + * or other {@code CharSequence}, a {@code Number}, a {@code Date}, + * a {@code Temporal}, a {@code UUID}, a {@code URI}, a {@code URL}, + * a {@code Locale}, or a {@code Class}. + *

{@code Void} and {@code void} are not considered simple value types. + * @param type the type to check + * @return whether the given type represents a "simple" value type + * @since 6.1 + */ + public static boolean isSimpleValueType(Class type) { + return (Void.class != type && void.class != type && + (isPrimitiveOrWrapper(type) || + Enum.class.isAssignableFrom(type) || + CharSequence.class.isAssignableFrom(type) || + Number.class.isAssignableFrom(type) || + Date.class.isAssignableFrom(type) || + Temporal.class.isAssignableFrom(type) || + UUID.class.isAssignableFrom(type) || + URI.class == type || + URL.class == type || + Locale.class == type || + Class.class == type)); + } + /** * Check if the right-hand side type may be assigned to the left-hand side * type, assuming setting by reflection. Considers primitive wrapper 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 fd4fb575883b..d7a9b2a008c5 100644 --- a/spring-core/src/main/java/org/springframework/util/ObjectUtils.java +++ b/spring-core/src/main/java/org/springframework/util/ObjectUtils.java @@ -17,17 +17,11 @@ package org.springframework.util; import java.lang.reflect.Array; -import java.net.URI; -import java.net.URL; -import java.time.temporal.Temporal; import java.util.Arrays; import java.util.Collection; -import java.util.Date; -import java.util.Locale; import java.util.Map; import java.util.Optional; import java.util.StringJoiner; -import java.util.UUID; import org.springframework.lang.Nullable; @@ -918,6 +912,7 @@ public static String nullSafeToString(@Nullable short[] array) { * @since 5.3.27 * @see #nullSafeToString(Object) * @see StringUtils#truncate(CharSequence) + * @see ClassUtils#isSimpleValueType(Class) */ public static String nullSafeConciseToString(@Nullable Object obj) { if (obj == null) { @@ -930,7 +925,7 @@ public static String nullSafeConciseToString(@Nullable Object obj) { return StringUtils.truncate(charSequence); } Class type = obj.getClass(); - if (isSimpleValueType(type)) { + if (ClassUtils.isSimpleValueType(type)) { String str = obj.toString(); if (str != null) { return StringUtils.truncate(str); @@ -939,22 +934,4 @@ public static String nullSafeConciseToString(@Nullable Object obj) { return type.getTypeName() + "@" + getIdentityHexString(obj); } - /** - * Derived from {@link org.springframework.beans.BeanUtils#isSimpleValueType}. - */ - private static boolean isSimpleValueType(Class type) { - return (Void.class != type && void.class != type && - (ClassUtils.isPrimitiveOrWrapper(type) || - Enum.class.isAssignableFrom(type) || - CharSequence.class.isAssignableFrom(type) || - Number.class.isAssignableFrom(type) || - Date.class.isAssignableFrom(type) || - Temporal.class.isAssignableFrom(type) || - UUID.class.isAssignableFrom(type) || - URI.class == type || - URL.class == type || - Locale.class == type || - Class.class == type)); - } - }