在看CallAdapter的时候,发现需要根据接口方法的Return Type,来选择合适的CallAdapter。所以有必要了解一下 Java Type基础。
Java Type有以下几种:
- 基本类型(Class):原始类型,每个类或接口都有个Class对象。
- 参数化类型(ParameterizedType): 就是我们平常所用到的泛型List<String>、Map<K, V>, Set<T>, Class<?>,ArrayList<? extends User>。
-
public interface ParameterizedType extends Type { // 获取<>中实际的类型参数,以Type数组形式返回 Type[] getActualTypeArguments(); // 获取<>前面的类型 Type getRawType(); // 如果这个类型是某个类型所属,则获取这个所有者的类型,否则返回null,比如Map.Entry<Sting,String>,会返回Map Type getOwnerType(); } - 泛型数组类型(GenericArrayType):用来描述ParameterizedType、TypeVariable类型的数组。 并不是我们工作中所使用的数组String[] 、byte[],而是带有泛型的数组,即List<T>[], T[]。
public interface GenericArrayType extends Type {
// 获得这个数组元素类型,比如T[] 则获得T的type
Type getGenericComponentType();
}
- 类型变量(TypeVariable):比如 T a。
public interface TypeVariable<D extends GenericDeclaration> extends Type, AnnotatedElement {
// 获取泛型的上限,无显示定义(extends),默认为Object
Type[] getBounds();
// 获取声明改类型变量实体(即获取类,方法或构造器名)
D getGenericDeclaration();
// 获取名称,即K、V、E之类名称
String getName();
AnnotatedType[] getAnnotatedBounds();
}
- 泛型表达式或者通配符表达式(WildcardType),即
? extends Number这样的表达式;WildcardType虽然是Type的子接口,但却不是Java类型中的一种。
public interface WildcardType extends Type {
// 获取泛型表达式上界(上限extends)
Type[] getUpperBounds();
// 获取泛型表达式下界(下限super)
Type[] getLowerBounds();
}
那么Retrofit是怎么解析Java Type的呢?
在Method方法中有一个getGenericReturnType()返回方法的Return Type。 这是Retrofit解析Return Type开端。
在ServiceMethod中对接口方法的返回类型做限制。
- Raw type, 比如,T, T[], <? extends User>, 不被允许。不能有泛行。
- ParamateredType, Call<T>, Call<? extends User>, T[] , 这几种方式都是不被允许的。不能有泛行。
- 总之就是不能有泛型。
- 最后还有void类型。
在create()方法中有对接口类型的检查,是调用了validateServiceInterface(), 其中candidate.getTypeParameters().length != 0就是检查是不是有泛型参数。有的话就抛异常了。像public interface IFileTransferService<T>是不被允许的。
private void validateServiceInterface(Class<?> service) {
if (!service.isInterface()) {
throw new IllegalArgumentException("API declarations must be interfaces.");
}
Deque<Class<?>> check = new ArrayDeque<>(1);
check.add(service);
while (!check.isEmpty()) {
Class<?> candidate = check.removeFirst();
if (candidate.getTypeParameters().length != 0) {
StringBuilder message =
new StringBuilder("Type parameters are unsupported on ").append(candidate.getName());
if (candidate != service) {
message.append(" which is an interface of ").append(service.getName());
}
throw new IllegalArgumentException(message.toString());
}
}
}
在生成HttpServiceMethod的过程中,也有对类型的检查。是通过Utils.hasUnresolvableType()方法进行的。
abstract class ServiceMethod<T> {
static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
Type returnType = method.getGenericReturnType();
if (Utils.hasUnresolvableType(returnType)) {
throw methodError(
method,
"Method return type must not include a type variable or wildcard: %s",
returnType);
}
if (returnType == void.class) {
throw methodError(method, "Service methods cannot return void.");
}
}
}
hasUnresolvableType()方法里面,已经限定了GenericArrayType, TypeVariable, WildcardType三种不能作为Return Type。
static boolean hasUnresolvableType(@Nullable Type type) {
if (type instanceof Class<?>) {
return false;
}
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
for (Type typeArgument : parameterizedType.getActualTypeArguments()) {
if (hasUnresolvableType(typeArgument)) {
return true;
}
}
return false;
}
if (type instanceof GenericArrayType) {
return hasUnresolvableType(((GenericArrayType) type).getGenericComponentType());
}
if (type instanceof TypeVariable) {
return true;
}
if (type instanceof WildcardType) {
return true;
}
String className = type == null ? "null" : type.getClass().getName();
throw new IllegalArgumentException(
"Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <"
+ type
+ "> is of type "
+ className);
}
Retrofit的Utils类,是非常好的工具类,以后用到相似的功能可以拿来用。
本文详细介绍了Retrofit如何解析JavaType,重点在于理解不同类型的JavaType,如基本类型、参数化类型、泛型数组类型、类型变量和通配符表达式。Retrofit在创建ServiceMethod时,会对接口方法的返回类型进行限制,不允许存在泛型。在`validateServiceInterface`和`parseAnnotations`方法中,通过检查`getGenericReturnType`和`hasUnresolvableType`来确保返回类型符合规范。Retrofit的Utils工具类在处理类型检查方面发挥了关键作用。
342

被折叠的 条评论
为什么被折叠?



