Mybatis技術內幕(2.3.7):反射模塊-TypeParameterResolver

基於Mybatis-3.5.0版本java

Type 接口

  爲何要單獨拿一篇文章來說呢?由於裏面涉及到的java-Type接口的內容以前沒有接觸和了解過。我相信在座的不少小夥伴也必定不知道其中的奧祕哦~
  你知道Class對象還有一個父接口嗎?apache

如下內容均摘錄自 徐郡明 《Mybatis技術內幕》數組

先簡單介紹一下Type接口的基礎知識。Type是全部類型的父接口,它有四個子接口和一個實現類,以下圖: ide

下面來看這些子接口和子類所表明的類型工具

  • Class比較常見,它表示的是原始類型。Class類的對象表示JVM中的一個類或者接口,每一個java類在JVM裏都表現爲一個Class對象。在程序中能夠經過「類型.class」、「對象.getClas()」或是「Class.forName("類名")」等方法獲取Class對象。數組也被映射爲Class對象,全部元素相同且維數相同的數組都共享同一個Class對象。
  • ParameterizedType表示的是參數化類型,例如List<String>、Map<Integer,String>、Service<User>這種帶有泛型的類型。ParameterizedType接口中經常使用的方法有三個,分別是:
    • Type getRawType()——返回參數化類型中的原始類型。例如List<String>的原始類型爲List
    • Type[] getActualTypeArguments()——獲取參數化類型的類型變量或是實際類型列表。例如Map<Integer,String>的實際泛型列表Integer和String。須要注意的是,該列表的類型都是Type,也就是說,可能存在多層嵌套的狀況。
    • Type getOwnerType()——返回的是類型所屬的類型,例如存在A<T>類,其中定義了內部類InnerA<T>,則Inner<A>所屬的類型A<T>,若是是頂層類型則返回null。這種關係比較常見的示例是Map<K,V>接口與Map.Entry<K,V>接口,Map<K,V>接口是Map.Entry<K,V>接口的全部者
  • TypeVariable表示的是類型變量,它用來反映在JVM編譯該泛型前的信息。例如List<T>中T就是類型變量,它在編譯是需被轉換爲一個具體的類型後才能正常使用。
    • Type[] getBounds()——獲取類型變量的上邊界,若是未明確聲明上邊界則默認爲Object。例如class Test<K extends Person>中K的上界就是Person。
    • D getGenericDeclaration()——獲取聲明該類型變量的原始類型,例如class Test<K extends Person>中的原始類型是Test。
    • String getName()——獲取在源碼中定義時的名字,上例中爲K。
  • GenericArrayType表示的是數組類型且組成的元素是ParameterizedType或TypeVariable。例如List<String>[]或T[]。該接口只有Type getGenericComponentType()一個方法,它返回數組的組成元素。
  • WildcardType表示通配符泛型,例如? extends Number和? super Integer。
    • Type[] getUpperBounds()破折號泛型變量的上界。
    • Type[] getLowerBounds()破折號泛型變量的下界。

1.0 TypeParameterResolver

org.apache.ibatis.reflection.TypeParameterResolver是一個主要用來負責解析字段類型、方法返回值類型和方法參數列表中各個參數的類型的一個工具類。代碼以下:單元測試

/** * 暴露了三個公用靜態方法,分別用於解析Field類型、Method返回類型、方法參數類型 * @author Iwao AVE! */
public class TypeParameterResolver {

	/** * 解析屬性類型 * @return The field type as {@link Type}. If it has type parameters in the * declaration,<br> * they will be resolved to the actual runtime {@link Type}s. */
	public static Type resolveFieldType(Field field, Type srcType) {
		// 屬性類型
		Type fieldType = field.getGenericType();
		// 定義的類
		Class<?> declaringClass = field.getDeclaringClass();
		// 解析類型
		return resolveType(fieldType, srcType, declaringClass);
	}

	/** * 解析方法返回值類型 * @return The return type of the method as {@link Type}. If it has type * parameters in the declaration,<br> * they will be resolved to the actual runtime {@link Type}s. */
	public static Type resolveReturnType(Method method, Type srcType) {
		// 返回值類型
		Type returnType = method.getGenericReturnType();
		// 定義的類
		Class<?> declaringClass = method.getDeclaringClass();
		// 解析類型
		return resolveType(returnType, srcType, declaringClass);
	}

	/** * 解析方法參數類型 * @return The parameter types of the method as an array of {@link Type}s. If * they have type parameters in the declaration,<br> * they will be resolved to the actual runtime {@link Type}s. */
	public static Type[] resolveParamTypes(Method method, Type srcType) {
		// 參數類型
		Type[] paramTypes = method.getGenericParameterTypes();
		// 定義的類
		Class<?> declaringClass = method.getDeclaringClass();
		Type[] result = new Type[paramTypes.length];
		for (int i = 0; i < paramTypes.length; i++) {
			// 解析類型
			result[i] = resolveType(paramTypes[i], srcType, declaringClass);
		}
		return result;
	}

	/** * 解析類型 * @param type 類型 * @param srcType 來源類型 * @param declaringClass 定義的類 * @return 解析後的類型 */
	private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
		if (type instanceof TypeVariable) {// 解析TypeVariable
			return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
		} else if (type instanceof ParameterizedType) {// 解析ParameterizedType
			return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
		} else if (type instanceof GenericArrayType) {// 解析GenericArrayType
			return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
		} else {
			return type;// Class類型直接返回
		}
	}

	private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType, Class<?> declaringClass) {
		Type componentType = genericArrayType.getGenericComponentType();
		Type resolvedComponentType = null;
		if (componentType instanceof TypeVariable) {
			resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
		} else if (componentType instanceof GenericArrayType) {
			resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
		} else if (componentType instanceof ParameterizedType) {
			resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType,
					declaringClass);
		}
		if (resolvedComponentType instanceof Class) {
			return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
		} else {
			return new GenericArrayTypeImpl(resolvedComponentType);
		}
	}

	/** * 解析 ParameterizedType 類型 * @param parameterizedType ParameterizedType 類型 * @param srcType 來源類型 * @param declaringClass 定義的類 * @return 解析後的類型 */
	private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType, Class<?> declaringClass) {
		Class<?> rawType = (Class<?>) parameterizedType.getRawType();
		// 解析 <> 中實際類型
		Type[] typeArgs = parameterizedType.getActualTypeArguments();
		Type[] args = new Type[typeArgs.length];
		for (int i = 0; i < typeArgs.length; i++) {
			if (typeArgs[i] instanceof TypeVariable) {
				args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
			} else if (typeArgs[i] instanceof ParameterizedType) {
				args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
			} else if (typeArgs[i] instanceof WildcardType) {
				args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
			} else {
				args[i] = typeArgs[i];
			}
		}
		return new ParameterizedTypeImpl(rawType, null, args);
	}

	private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
		Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);
		Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);
		return new WildcardTypeImpl(lowerBounds, upperBounds);
	}

	private static Type[] resolveWildcardTypeBounds(Type[] bounds, Type srcType, Class<?> declaringClass) {
		Type[] result = new Type[bounds.length];
		for (int i = 0; i < bounds.length; i++) {
			if (bounds[i] instanceof TypeVariable) {
				result[i] = resolveTypeVar((TypeVariable<?>) bounds[i], srcType, declaringClass);
			} else if (bounds[i] instanceof ParameterizedType) {
				result[i] = resolveParameterizedType((ParameterizedType) bounds[i], srcType, declaringClass);
			} else if (bounds[i] instanceof WildcardType) {
				result[i] = resolveWildcardType((WildcardType) bounds[i], srcType, declaringClass);
			} else {
				result[i] = bounds[i];
			}
		}
		return result;
	}

	/** * 解析TypeVariable類型 * @param typeVar * @param srcType * @param declaringClass * @return */
	private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
		Type result = null;
		Class<?> clazz = null;
		if (srcType instanceof Class) {
			clazz = (Class<?>) srcType;
		} else if (srcType instanceof ParameterizedType) {
			ParameterizedType parameterizedType = (ParameterizedType) srcType;
			clazz = (Class<?>) parameterizedType.getRawType();
		} else {
			throw new IllegalArgumentException(
					"The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
		}

		if (clazz == declaringClass) {
			Type[] bounds = typeVar.getBounds();
			if (bounds.length > 0) {
				return bounds[0];
			}
			return Object.class;
		}

		Type superclass = clazz.getGenericSuperclass();
		result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
		if (result != null) {
			return result;
		}

		Type[] superInterfaces = clazz.getGenericInterfaces();
		for (Type superInterface : superInterfaces) {
			result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
			if (result != null) {
				return result;
			}
		}
		return Object.class;
	}

	private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz, Type superclass) {
		if (superclass instanceof ParameterizedType) {
			ParameterizedType parentAsType = (ParameterizedType) superclass;
			Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
			TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();
			if (srcType instanceof ParameterizedType) {
				parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
			}
			if (declaringClass == parentAsClass) {
				for (int i = 0; i < parentTypeVars.length; i++) {
					if (typeVar == parentTypeVars[i]) {
						return parentAsType.getActualTypeArguments()[i];
					}
				}
			}
			if (declaringClass.isAssignableFrom(parentAsClass)) {
				return resolveTypeVar(typeVar, parentAsType, declaringClass);
			}
		} else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
			return resolveTypeVar(typeVar, superclass, declaringClass);
		}
		return null;
	}

	private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass, ParameterizedType parentType) {
		Type[] parentTypeArgs = parentType.getActualTypeArguments();
		Type[] srcTypeArgs = srcType.getActualTypeArguments();
		TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();
		Type[] newParentArgs = new Type[parentTypeArgs.length];
		boolean noChange = true;
		for (int i = 0; i < parentTypeArgs.length; i++) {
			if (parentTypeArgs[i] instanceof TypeVariable) {
				for (int j = 0; j < srcTypeVars.length; j++) {
					if (srcTypeVars[j] == parentTypeArgs[i]) {
						noChange = false;
						newParentArgs[i] = srcTypeArgs[j];
					}
				}
			} else {
				newParentArgs[i] = parentTypeArgs[i];
			}
		}
		return noChange ? parentType
				: new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
	}

	private TypeParameterResolver() {
		super();
	}

	static class ParameterizedTypeImpl implements ParameterizedType {
		private Class<?> rawType;

		private Type ownerType;

		private Type[] actualTypeArguments;

		public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
			super();
			this.rawType = rawType;
			this.ownerType = ownerType;
			this.actualTypeArguments = actualTypeArguments;
		}

		@Override
		public Type[] getActualTypeArguments() {
			return actualTypeArguments;
		}

		@Override
		public Type getOwnerType() {
			return ownerType;
		}

		@Override
		public Type getRawType() {
			return rawType;
		}

		@Override
		public String toString() {
			return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments="
					+ Arrays.toString(actualTypeArguments) + "]";
		}
	}

	static class WildcardTypeImpl implements WildcardType {
		private Type[] lowerBounds;

		private Type[] upperBounds;

		WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
			super();
			this.lowerBounds = lowerBounds;
			this.upperBounds = upperBounds;
		}

		@Override
		public Type[] getLowerBounds() {
			return lowerBounds;
		}

		@Override
		public Type[] getUpperBounds() {
			return upperBounds;
		}
	}

	static class GenericArrayTypeImpl implements GenericArrayType {
		private Type genericComponentType;

		GenericArrayTypeImpl(Type genericComponentType) {
			super();
			this.genericComponentType = genericComponentType;
		}

		@Override
		public Type getGenericComponentType() {
			return genericComponentType;
		}
	}
}
複製代碼

2.0 總結

  能夠經過調試org.apache.ibatis.reflection.TypeParameterResolverTest這個單元測試類,觸發不一樣的場景去深刻了解Java-Type。   測試

失控的阿甘,樂於分享,記錄點滴this

相關文章
相關標籤/搜索