private @Nullable ParameterHandler> parseParameter(
int p, Type parameterType, @Nullable Annotation[] annotations, boolean allowContinuation) {
ParameterHandler> result = null;
if (annotations != null) {
for (Annotation annotation : annotations) {
//核心就是这一句,实际上就是把前面获取到的参数类型数组与注解数组匹配
ParameterHandler> annotationAction = parseParameterAnnotation(p, parameterType, annotations, annotation);
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(method, p,
"Multiple Retrofit annotations found, only one allowed.");
}
result = annotationAction;
}
}
if (result == null) {
if (allowContinuation) {
try {
if (Utils.getRawType(parameterType) == Continuation.class) {
isKotlinSuspendFunction = true;
return null;
}
} catch (NoClassDefFoundError ignored) {
}
}
throw parameterError(method, p, "No Retrofit annotation found.");
}
return result;
}
紧接上文,我们来看看Service接口中的参数注解是怎样处理的。
涉及到的两项验证
不确定的类型检查
首先来看validateResolvableType
方法,其实是对参数的类型包括范型的检查。
private void validateResolvableType(int p, Type type) {
if (Utils.hasUnresolvableType(type)) {
throw parameterError(method, p,
"Parameter type must not include a type variable or wildcard: %s", 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);
}
看到这真的醉了,特意去了解了一下这里面都是什么东西然后发现,只有两类Type是不可取的:
- TypeVariable,写法如:
TestReflect
- WildcardType,写法如:
List extends TestReflect>
那么我们可以看到,上面两种类型的type都是类型不确定的。
pathName路径名称校验
private void validatePathName(int p, String name) {
if (!PARAM_NAME_REGEX.matcher(name).matches()) {
throw parameterError(method, p, "@Path parameter name must match %s. Found: %s",
PARAM_URL_REGEX.pattern(), name);
}
// Verify URL replacement name is actually present in the URL path.
if (!relativeUrlParamNames.contains(name)) {
throw parameterError(method, p, "URL \"%s\" does not contain \"{%s}\".", relativeUrl, name);
}
}
对各种注解的处理
其实都差不多,这里以第一个Url注解为例。
Url注解
if (annotation instanceof Url) {
validateResolvableType(p, type);
if (gotUrl) {
throw parameterError(method, p, "Multiple @Url method annotations found.");
}
if (gotPath) {
throw parameterError(method, p, "@Path parameters may not be used with @Url.");
}
if (gotQuery) {
throw parameterError(method, p, "A @Url parameter must not come after a @Query.");
}
if (gotQueryName) {
throw parameterError(method, p, "A @Url parameter must not come after a @QueryName.");
}
if (gotQueryMap) {
throw parameterError(method, p, "A @Url parameter must not come after a @QueryMap.");
}
if (relativeUrl != null) {
throw parameterError(method, p, "@Url cannot be used with @%s URL", httpMethod);
}
gotUrl = true;
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && "android.net.Uri".equals(((Class>) type).getName()))) {
return new ParameterHandler.RelativeUrl(method, p);
} else {
throw parameterError(method, p,
"@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
}
}
从上述代码可以看出,经过层层检查,最后就是返回了一个RelativeUrl对象,这个对象继承自ParameterHandler
:
abstract class ParameterHandler {
abstract void apply(RequestBuilder builder, @Nullable T value) throws IOException;
final ParameterHandler> iterable() {
return new ParameterHandler>() {
@Override void apply(RequestBuilder builder, @Nullable Iterable values)
throws IOException {
if (values == null) return; // Skip null values.
for (T value : values) {
ParameterHandler.this.apply(builder, value);
}
}
};
}
final ParameterHandler
这是一个抽象类,排除掉所有子类后,只含有三个方法:
- apply(RequestBuilder builder, @Nullable T value):虚方法,组装RequestBuilder。那么所有的子类都需要实现这个方法,且每个子类的实现都不同。但是每种实现都只有一个共同的目的,就是给RequestBuilder中的属性赋值,这个值是从参数传递来的。
- iterable():实例方法,循环组装builder。当参数为
Iterable
类型时,通过循环调用apply
方法来组装Builder。 - array():同
iterable
方法,这不过这里是对数组的处理。
那么我们就可以知道,ParameterHandler
这个类,或者说serverApi接口中定义的方法参数的注解的作用就是组装一个RequestBuilder,那么他所有的子类当然也是干了这么一件事,所以,这特么不就是外观模式么!那么这个RequestBuilder是用来生成谁呢?当然就是Okhttp中的Request
。
未完,来项目了,待续吧。。。