From f0472ea1c09e3308627746b62b91d620d16a6608 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Mon, 23 Mar 2026 20:11:54 +0100 Subject: [PATCH] Polishing (includes nullable declaration for internal type array) --- .../org/springframework/util/TypeUtils.java | 47 +++++++------------ 1 file changed, 17 insertions(+), 30 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/util/TypeUtils.java b/spring-core/src/main/java/org/springframework/util/TypeUtils.java index 5fa6ae0214a..ed0c4ee369d 100644 --- a/spring-core/src/main/java/org/springframework/util/TypeUtils.java +++ b/spring-core/src/main/java/org/springframework/util/TypeUtils.java @@ -38,15 +38,16 @@ import org.springframework.lang.Contract; */ public abstract class TypeUtils { - private static final Type[] IMPLICIT_LOWER_BOUNDS = { null }; + private static final @Nullable Type[] IMPLICIT_LOWER_BOUNDS = { null }; private static final Type[] IMPLICIT_UPPER_BOUNDS = { Object.class }; + /** * Check if the right-hand side type may be assigned to the left-hand side * type following the Java generics rules. - * @param lhsType the target type (left-hand side (LHS) type) - * @param rhsType the value type (right-hand side (RHS) type) that should + * @param lhsType the target type (left-hand side type) + * @param rhsType the value type (right-hand side type) that should * be assigned to the target type * @return {@code true} if {@code rhsType} is assignable to {@code lhsType} * @see ClassUtils#isAssignable(Class, Class) @@ -55,37 +56,34 @@ public abstract class TypeUtils { Assert.notNull(lhsType, "Left-hand side type must not be null"); Assert.notNull(rhsType, "Right-hand side type must not be null"); - // all types are assignable to themselves and to class Object + // All types are assignable to themselves and to class Object. if (lhsType.equals(rhsType) || Object.class == lhsType) { return true; } if (lhsType instanceof Class lhsClass) { - // just comparing two classes + // Just comparing two classes... if (rhsType instanceof Class rhsClass) { return ClassUtils.isAssignable(lhsClass, rhsClass); } if (rhsType instanceof ParameterizedType rhsParameterizedType) { Type rhsRaw = rhsParameterizedType.getRawType(); - - // a parameterized type is always assignable to its raw class type + // A parameterized type is always assignable to its raw class type. if (rhsRaw instanceof Class rhRawClass) { return ClassUtils.isAssignable(lhsClass, rhRawClass); } } else if (lhsClass.isArray() && rhsType instanceof GenericArrayType rhsGenericArrayType) { Type rhsComponent = rhsGenericArrayType.getGenericComponentType(); - return isAssignable(lhsClass.componentType(), rhsComponent); } } - // parameterized types are only assignable to other parameterized types and class types + // Parameterized types are only assignable to other parameterized types and class types. if (lhsType instanceof ParameterizedType lhsParameterizedType) { if (rhsType instanceof Class rhsClass) { Type lhsRaw = lhsParameterizedType.getRawType(); - if (lhsRaw instanceof Class lhsClass) { return ClassUtils.isAssignable(lhsClass, rhsClass); } @@ -97,7 +95,6 @@ public abstract class TypeUtils { if (lhsType instanceof GenericArrayType lhsGenericArrayType) { Type lhsComponent = lhsGenericArrayType.getGenericComponentType(); - if (rhsType instanceof Class rhsClass && rhsClass.isArray()) { return isAssignable(lhsComponent, rhsClass.componentType()); } @@ -122,7 +119,6 @@ public abstract class TypeUtils { Type[] lhsTypeArguments = lhsType.getActualTypeArguments(); Type[] rhsTypeArguments = rhsType.getActualTypeArguments(); - if (lhsTypeArguments.length != rhsTypeArguments.length) { return false; } @@ -130,7 +126,6 @@ public abstract class TypeUtils { for (int size = lhsTypeArguments.length, i = 0; i < size; ++i) { Type lhsArg = lhsTypeArguments[i]; Type rhsArg = rhsTypeArguments[i]; - if (!lhsArg.equals(rhsArg) && !(lhsArg instanceof WildcardType wildcardType && isAssignable(wildcardType, rhsArg))) { return false; @@ -141,17 +136,14 @@ public abstract class TypeUtils { } private static boolean isAssignable(WildcardType lhsType, Type rhsType) { - Type[] lUpperBounds = getUpperBounds(lhsType); - - Type[] lLowerBounds = getLowerBounds(lhsType); + @Nullable Type[] lUpperBounds = getUpperBounds(lhsType); + @Nullable Type[] lLowerBounds = getLowerBounds(lhsType); if (rhsType instanceof WildcardType rhsWcType) { - // both the upper and lower bounds of the right-hand side must be - // completely enclosed in the upper and lower bounds of the left- - // hand side. - Type[] rUpperBounds = getUpperBounds(rhsWcType); - - Type[] rLowerBounds = getLowerBounds(rhsWcType); + // Both the upper and lower bounds of the right-hand side must be + // completely enclosed in the upper and lower bounds of the left-hand side. + @Nullable Type[] rUpperBounds = getUpperBounds(rhsWcType); + @Nullable Type[] rLowerBounds = getLowerBounds(rhsWcType); for (Type lBound : lUpperBounds) { for (Type rBound : rUpperBounds) { @@ -159,7 +151,6 @@ public abstract class TypeUtils { return false; } } - for (Type rBound : rLowerBounds) { if (!isAssignableBound(lBound, rBound)) { return false; @@ -173,7 +164,6 @@ public abstract class TypeUtils { return false; } } - for (Type rBound : rLowerBounds) { if (!isAssignableBound(rBound, lBound)) { return false; @@ -187,7 +177,6 @@ public abstract class TypeUtils { return false; } } - for (Type lBound : lLowerBounds) { if (!isAssignableBound(rhsType, lBound)) { return false; @@ -198,17 +187,15 @@ public abstract class TypeUtils { return true; } - private static Type[] getLowerBounds(WildcardType wildcardType) { + private static @Nullable Type[] getLowerBounds(WildcardType wildcardType) { Type[] lowerBounds = wildcardType.getLowerBounds(); - - // supply the implicit lower bound if none are specified + // Supply the implicit lower bound if none are specified. return (lowerBounds.length == 0 ? IMPLICIT_LOWER_BOUNDS : lowerBounds); } private static Type[] getUpperBounds(WildcardType wildcardType) { Type[] upperBounds = wildcardType.getUpperBounds(); - - // supply the implicit upper bound if none are specified + // Supply the implicit upper bound if none are specified. return (upperBounds.length == 0 ? IMPLICIT_UPPER_BOUNDS : upperBounds); }