Call的类型 T 即Response的类型 T,获得了Call就能够正确输出给Response。那么Retrofit是怎么做到的呢?
以下是HttpServiceMethod中的 static 方法:
static HttpServiceMethod parseAnnotations(
Retrofit retrofit, Method method, RequestFactory requestFactory) {
// 省略部分代码
// ...
Type adapterType;
// 解析 kotlin 语言中的返回值
if (isKotlinSuspendFunction) {
Type[] parameterTypes = method.getGenericParameterTypes();
Type responseType = Utils.getParameterLowerBound(0,
(ParameterizedType) parameterTypes[parameterTypes.length - 1]);
if (getRawType(responseType) == Response.class && responseType instanceof ParameterizedType) {
// Unwrap the actual body type from Response.
responseType = Utils.getParameterUpperBound(0, (ParameterizedType) responseType);
continuationWantsResponse = true;
} else {
// TODO figure out if type is nullable or not
// Metadata metadata = method.getDeclaringClass().getAnnotation(Metadata.class)
// Find the entry for method
// Determine if return type is nullable or not
}
adapterType = new Utils.ParameterizedTypeImpl(null, Call.class, responseType);
annotations = SkipCallbackExecutorImpl.ensurePresent(annotations);
} else {
// 解析 java 语言写的返回值(写过的都知道,这个很容易懂了)
adapterType = method.getGenericReturnType();
}
// 省略部分代码
// ...
}
拿到adapterType之后,又辗转调用了CallAdapter.Factory. get()以创建实现了CallAdapter接口的CallAdapter:
public interface CallAdapter {
// 省略部分代码
// ...
abstract class Factory {
public abstract @Nullable CallAdapter, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit);
// ...
}
}
注意前面的adapterType是Call,所以要取出里面的T,才是真正要传给 Gson 从而输出的类型:
// 这是 CallAdapter.Factory. get() 的 impl
@Override public @Nullable CallAdapter, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
if (getRawType(returnType) != Call.class) {
return null;
}
if (!(returnType instanceof ParameterizedType)) {
throw new IllegalArgumentException("Call return type must be parameterized as Call or Call extends Foo>");
}
final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);
// ...
// 在这里 CallAdapter 接口的实现
return new CallAdapter>() {
@Override public Type responseType() {
return responseType;
}
// ...
};
}
Call有类似 GsonTypeToken的功能,如:
@KeepV
data class Data(val users: List)
@KeepV
data class User(val id: Long)
interface AaaService {
@GET("a/b/c.json")
fun getAbc(): Call>
}
能够正确解析出Data,相当于new TypeToken>{}.getType(),所以能传给 Gson 从而 输入正确的Response>。细节就不多讲了,这里主要是做个笔记备忘。
题外话:
由于类型参数的 不可传递性,即:
Type getType(T user) {
return new TypeToken{}.getType()
}
// 拿不到 Data 和 User 的类型
getType(new Data())
而Data.class这种写法不能编译通过(kotlin里面可以),因此Data类内部不能拿到User类型,所以必须以某类的 运行时子类 + 泛型参数 的方式(Java 反射的实现如此,没有什么原理可讲)即new TypeToken>{}.getType()同时拿到Data和User(如果有更多泛型嵌套也可以拿到)的类型信息,所以才有了TypeToken。
这从一个侧面说明了只要这种 字面量 Data的写法能够编译通过(无论是用作返回值还是参数化类型),都有办法拿到实际类型。细心的人可能发现了上例中的val users: List,这里值类型List不是 字面量,但 Gson 也能拿到实际类型User,这也说明了只要在泛型类实例化时写了 字面量 的参数化类型,那么该类体中的一切类型占位符的实际类型也有办法拿到。
关于笔者运用这个规则而实现的一个框架见这里。