spring TypeUtils 源码

  • 2022-08-08
  • 浏览 (271)

spring TypeUtils 代码

文件路径:/spring-core/src/main/java/org/springframework/util/TypeUtils.java

/*
 * Copyright 2002-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.util;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.WildcardType;

import org.springframework.lang.Nullable;

/**
 * Utility to work with generic type parameters.
 *
 * <p>Mainly for internal use within the framework.
 *
 * @author Ramnivas Laddad
 * @author Juergen Hoeller
 * @author Chris Beams
 * @author Sam Brannen
 * @since 2.0.7
 */
public abstract class TypeUtils {

	/**
	 * 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
	 * @param rhsType the value type that should be assigned to the target type
	 * @return true if rhs is assignable to lhs
	 */
	public static boolean isAssignable(Type lhsType, Type rhsType) {
		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
		if (lhsType.equals(rhsType) || Object.class == lhsType) {
			return true;
		}

		if (lhsType instanceof Class<?> lhsClass) {
			// 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
				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.getComponentType(), rhsComponent);
			}
		}

		// 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);
				}
			}
			else if (rhsType instanceof ParameterizedType rhsParameterizedType) {
				return isAssignable(lhsParameterizedType, rhsParameterizedType);
			}
		}

		if (lhsType instanceof GenericArrayType lhsGenericArrayType) {
			Type lhsComponent = lhsGenericArrayType.getGenericComponentType();

			if (rhsType instanceof Class<?> rhsClass && rhsClass.isArray()) {
				return isAssignable(lhsComponent, rhsClass.getComponentType());
			}
			else if (rhsType instanceof GenericArrayType rhsGenericArrayType) {
				Type rhsComponent = rhsGenericArrayType.getGenericComponentType();

				return isAssignable(lhsComponent, rhsComponent);
			}
		}

		if (lhsType instanceof WildcardType lhsWildcardType) {
			return isAssignable(lhsWildcardType, rhsType);
		}

		return false;
	}

	private static boolean isAssignable(ParameterizedType lhsType, ParameterizedType rhsType) {
		if (lhsType.equals(rhsType)) {
			return true;
		}

		Type[] lhsTypeArguments = lhsType.getActualTypeArguments();
		Type[] rhsTypeArguments = rhsType.getActualTypeArguments();

		if (lhsTypeArguments.length != rhsTypeArguments.length) {
			return false;
		}

		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;
			}
		}

		return true;
	}

	private static boolean isAssignable(WildcardType lhsType, Type rhsType) {
		Type[] lUpperBounds = lhsType.getUpperBounds();

		// supply the implicit upper bound if none are specified
		if (lUpperBounds.length == 0) {
			lUpperBounds = new Type[] { Object.class };
		}

		Type[] lLowerBounds = lhsType.getLowerBounds();

		// supply the implicit lower bound if none are specified
		if (lLowerBounds.length == 0) {
			lLowerBounds = new Type[] { null };
		}

		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 = rhsWcType.getUpperBounds();

			if (rUpperBounds.length == 0) {
				rUpperBounds = new Type[] { Object.class };
			}

			Type[] rLowerBounds = rhsWcType.getLowerBounds();

			if (rLowerBounds.length == 0) {
				rLowerBounds = new Type[] { null };
			}

			for (Type lBound : lUpperBounds) {
				for (Type rBound : rUpperBounds) {
					if (!isAssignableBound(lBound, rBound)) {
						return false;
					}
				}

				for (Type rBound : rLowerBounds) {
					if (!isAssignableBound(lBound, rBound)) {
						return false;
					}
				}
			}

			for (Type lBound : lLowerBounds) {
				for (Type rBound : rUpperBounds) {
					if (!isAssignableBound(rBound, lBound)) {
						return false;
					}
				}

				for (Type rBound : rLowerBounds) {
					if (!isAssignableBound(rBound, lBound)) {
						return false;
					}
				}
			}
		}
		else {
			for (Type lBound : lUpperBounds) {
				if (!isAssignableBound(lBound, rhsType)) {
					return false;
				}
			}

			for (Type lBound : lLowerBounds) {
				if (!isAssignableBound(rhsType, lBound)) {
					return false;
				}
			}
		}

		return true;
	}

	public static boolean isAssignableBound(@Nullable Type lhsType, @Nullable Type rhsType) {
		if (rhsType == null) {
			return true;
		}
		if (lhsType == null) {
			return false;
		}
		return isAssignable(lhsType, rhsType);
	}

}

相关信息

spring 源码目录

相关文章

spring AlternativeJdkIdGenerator 源码

spring AntPathMatcher 源码

spring Assert 源码

spring AutoPopulatingList 源码

spring Base64Utils 源码

spring ClassUtils 源码

spring CollectionUtils 源码

spring CommonsLogWriter 源码

spring CompositeIterator 源码

spring ConcurrencyThrottleSupport 源码

0  赞