简介
retrofit 是 square 出品的一个优秀的网络框架,注意,不是一个网络引擎。它的定位和 Volley 是一样的。
它完成了封装请求,线程切换,数据装换等一系列工作,如果自己有能力也可以封装一个这种框架,本质上是没有区别的。
retrofit 使用的网络引擎是 OkHttp.
而 OKHttp 和 HTTPClient,HttpUrlConnection 是一个级别的。
使用
//1 创建网络请求接口类
public interface GitHubService {
@GET(“users/{user}/repos”)
Call<List<Repo>> listRepos(@Path(“user”) String user);
}
//2 创建 Retrofit 实例对象
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(“https://api.github.com/”)
.build();
//3 通过动态代理创建网络接口代理对象
GitHubService service = retrofit.create(GitHubService.class);
//4 获取 Call 对象
Call<List<Repo>> repos = service.listRepos(“octocat”);
//5 执行同步请求或异步请求
repos.execute();
repos.enqueue(callback)
Retrofit 要求必须将请求 API 写到一个 interface 接口文件里,这是动态代理特性要求的。
从接口文件里我们可以看到,我们将每个请求用这种形式表达
public interface GitHubService {
@GET(“users/{user}/repos”)
Call<List<Repo>> listRepos(@Path(“user”) String user);
}
从接口文件我们可以看出,一个请求接口被各种注解所表示。
我们知道一个方法有一下关键字段组成
首先一个方法必须有描述符,返回值,方法名,参数类型,参数构成。
那我们用一个方法表示一个 http 请求需要哪些东西呢?
Http 请求,首先我们得知道是 GET 请求还是 POST 请求,
然后就是请求头信息,请求路径,查询参数等等。
POST 请求还需要 Body。
Retrofit 已经提供了足够的注解来表示一个方法。
Retrofit 的核心思想 AOP,面向切面变成,通过动态代理的反射,将接口文件里的每个方法记性处理,也就是分析该方法的注解生成一个 ServiceMethod 类。
Retrofit 里有个关键的类,ServiceMethod
@SuppressWarnings(“unchecked”) // Single-interface proxy creation guarded by parameter safety.
public <T> T create(final Class<T> service) {
Utils.validateServiceInterface(service);
if (validateEagerly) {
eagerlyValidateMethods(service);
}
return (T) Proxy.newProxyInstance(service.getClassLoader(), new Class<?>[] { service},
new InvocationHandler() {
private final Platform platform = Platform.get();
@Override public Object invoke(Object proxy, Method method, Object… args)
throws Throwable {
// If the method is a method from Object then defer to normal invocation.
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
// 创建 ServiceMethod 对象
ServiceMethod serviceMethod = loadServiceMethod(method);
OkHttpCall okHttpCall = new OkHttpCall<>(serviceMethod, args);
return serviceMethod.callAdapter.adapt(okHttpCall);
}
});
}
从第 3 步我们可以看出 create 方法的实现就是使用了动态代理,在运行时生成了 GitHubService 对象。
// 创建 ServiceMethod 对象 ServiceMethod serviceMethod = loadServiceMethod(method);
ServiceMethod loadServiceMethod(Method method) {
ServiceMethod result;
synchronized (serviceMethodCache) {
// 先从换从中取改方法对应的 ServiceMethod 对象,如果为 null 就构建一个 ServiceMethod 对象并存入到 map 中,如果不为 null 直接返回
result = serviceMethodCache.get(method);
if (result == null) {
result = new ServiceMethod.Builder(this, method).build();
serviceMethodCache.put(method, result);
}
}
return result;
}
我们可以看到 loadServiceMethod(Method method) 方法返回了一个 ServiceMethod 对象 这个 serviceMethodCache 对象是 Retrofit 的一个字段,是一个 Map 集合。
private final Map<Method, ServiceMethod> serviceMethodCache = new LinkedHashMap<>();
将接口文件里每个方法转换为一个 ServiceMethod 对象后放入改 map 中作为缓存,下次调用该方法后就不用再次解析改方法对象了,直接从改 map 里去以方法为 key 去取对应的 ServiceMethod 就行了。666
接下来看一下 ServiceMethod 对象的构造
ServiceMethod
final class ServiceMethod<T> {
// Upper and lower characters, digits, underscores, and hyphens, starting with a character.
static final String PARAM = “[a-zA-Z][a-zA-Z0-9_-]*”;
static final Pattern PARAM_URL_REGEX = Pattern.compile(“\\{(” + PARAM + “)\\}”);
static final Pattern PARAM_NAME_REGEX = Pattern.compile(PARAM);
final okhttp3.Call.Factory callFactory;
final CallAdapter<?> callAdapter;
private final HttpUrl baseUrl; 主机地址
private final Converter<ResponseBody, T> responseConverter;
private final String httpMethod;
private final String relativeUrl; 相对路径
private final Headers headers; 请求头部信息
private final MediaType contentType; 请求参数类型
private final boolean hasBody; 是否有请求体
private final boolean isFormEncoded; 是否是格式化的表单
private final boolean isMultipart; 是不是分块
private final ParameterHandler<?>[] parameterHandlers;
ServiceMethod(Builder<T> builder) {
this.callFactory = builder.retrofit.callFactory();
this.callAdapter = builder.callAdapter;
this.baseUrl = builder.retrofit.baseUrl();
this.responseConverter = builder.responseConverter;
this.httpMethod = builder.httpMethod;
this.relativeUrl = builder.relativeUrl;
this.headers = builder.headers;
this.contentType = builder.contentType;
this.hasBody = builder.hasBody;
this.isFormEncoded = builder.isFormEncoded;
this.isMultipart = builder.isMultipart;
this.parameterHandlers = builder.parameterHandlers;
}
}
ServiceMethod 是采用 Builder 模式创建的。
static final class Builder<T> {
final Retrofit retrofit;
final Method method; // 接口里生命的方法
final Annotation[] methodAnnotations; // 方法的注解,get/post/header 之类的
final Annotation[][] parameterAnnotationsArray; // 方法的参数注解数组,二维数组
final Type[] parameterTypes; // 方法的参数数组
Type responseType;
boolean gotField;
boolean gotPart;
boolean gotBody;
boolean gotPath;
boolean gotQuery;
boolean gotUrl;
String httpMethod;
boolean hasBody;
boolean isFormEncoded;
boolean isMultipart;
String relativeUrl;
Headers headers;
MediaType contentType;
Set<String> relativeUrlParamNames;
ParameterHandler<?>[] parameterHandlers;
Converter<ResponseBody, T> responseConverter;
CallAdapter<?> callAdapter;
public Builder(Retrofit retrofit, Method method) {
this.retrofit = retrofit;
this.method = method;
this.methodAnnotations = method.getAnnotations(); // 获取方法的注解
this.parameterTypes = method.getGenericParameterTypes(); // 获取被注解修饰的方法,一个数组
this.parameterAnnotationsArray = method.getParameterAnnotations(); // 获取方法的参数注解信息,是一个二维数组
}
Builder 的构造参数需要一个 Retrofit 对象和一个 Method 对象。
首先解析方法对象,将其注解和参数注解放到对应的数组里。
首先在构造方法里获取该方法的注解, 方法的参数,以及每个参数的注解。
关键就在 build 方法,在 build 方法里对方法做了一个彻底的分解
解析方法注解
public ServiceMethod build() {
callAdapter = createCallAdapter();
responseType = callAdapter.responseType();
if (responseType == Response.class || responseType == okhttp3.Response.class) {
throw methodError(“‘”
+ Utils.getRawType(responseType).getName()
+ “‘ is not a valid response body type. Did you mean ResponseBody?”);
}
responseConverter = createResponseConverter();
// 1 提取方法的注解
for (Annotation annotation : methodAnnotations) {
parseMethodAnnotation(annotation);
}
// 如果 httpMethod 为 null,即没有使用方法类型注解修饰,抛出异常进行提示
if (httpMethod == null) {
throw methodError(“HTTP method annotation is required (e.g., @GET, @POST, etc.).”);
}
// 如果没有请求体,即使用了 GET,HEAD,DELETE,OPTIONS 等所修饰,即不涉及到表单的提交,但是同时使用了 Multipart,或者 FormUrlEncoded 所修饰,就报错
if (!hasBody) {
if (isMultipart) {
throw methodError(
“Multipart can only be specified on HTTP methods with request body (e.g., @POST).”);
}
if (isFormEncoded) {
throw methodError(“FormUrlEncoded can only be specified on HTTP methods with ”
+ “request body (e.g., @POST).”);
}
}
// 2 提取方法的参数
int parameterCount = parameterAnnotationsArray.length;
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p];
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, “Parameter type must not include a type variable or wildcard: %s”,
parameterType);
}
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, “No Retrofit annotation found.”);
}
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
// 相对路径为 null 且 gotURL 为 false 的话,抛出异常,因为没有相对路径无法请求。
if (relativeUrl == null && !gotUrl) {
throw methodError(“Missing either @%s URL or @Url parameter.”, httpMethod);
}
// 没有使用 @FormUrlEncoded,@Multipart 主机并且 hasBody 为 false,但是 gotBody 为 true,抛出异常,提示
Non-Body 类型的 HTTP method 不能参数不能使用 @Body 注解
if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
throw methodError(“Non-body HTTP method cannot contain @Body.”);
}
// 使用 @FormUrlEncoded 修饰的方法中的参数至少有一个参数被 @Field 注解修饰
if (isFormEncoded && !gotField) {
throw methodError(“Form-encoded method must contain at least one @Field.”);
}
// 使用 @Multipart 修饰的方法中的参数至少有一个参数被 @Part 注解修饰
if (isMultipart && !gotPart) {
throw methodError(“Multipart method must contain at least one @Part.”);
}
// 当前 Builder 对象初始化完毕,可以用来够着 ServiceMethod 对象。
return new ServiceMethod<>(this);
}
1 处处理方法的注解,就是先处理 GET/POST/Header 等注解信息
private void parseMethodAnnotation(Annotation annotation) {
if (annotation instanceof DELETE) {
parseHttpMethodAndPath(“DELETE”, ((DELETE) annotation).value(), false);
} else if (annotation instanceof GET) {
parseHttpMethodAndPath(“GET”, ((GET) annotation).value(), false);
} else if (annotation instanceof HEAD) {
parseHttpMethodAndPath(“HEAD”, ((HEAD) annotation).value(), false);
if (!Void.class.equals(responseType)) {
throw methodError(“HEAD method must use Void as response type.”);
}
} else if (annotation instanceof PATCH) {
parseHttpMethodAndPath(“PATCH”, ((PATCH) annotation).value(), true);
} else if (annotation instanceof POST) {
parseHttpMethodAndPath(“POST”, ((POST) annotation).value(), true);
} else if (annotation instanceof PUT) {
parseHttpMethodAndPath(“PUT”, ((PUT) annotation).value(), true);
} else if (annotation instanceof OPTIONS) {
parseHttpMethodAndPath(“OPTIONS”, ((OPTIONS) annotation).value(), false);
} else if (annotation instanceof HTTP) {
HTTP http = (HTTP) annotation;
parseHttpMethodAndPath(http.method(), http.path(), http.hasBody());
} else if (annotation instanceof retrofit2.http.Headers) {
headers 注解
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
if (headersToParse.length == 0) {
throw methodError(“@Headers annotation is empty.”);
}
headers = parseHeaders(headersToParse);
} else if (annotation instanceof Multipart) {// 如果是 Multipart 注解
if (isFormEncoded) {
// 如果同时使用了 FormUrlEncoded 注解报错
throw methodError(“Only one encoding annotation is allowed.”);
}
isMultipart = true;
} else if (annotation instanceof FormUrlEncoded) {
if (isMultipart) {
// 如果同时使用了 Multipart 注解报错, 从这我们可以看出一个方法不能同时被 Multipart 和 FormUrlEncoded 所修饰
throw methodError(“Only one encoding annotation is allowed.”);
}
isFormEncoded = true;
}
}
然后根据具体的注解类型,在做进一步的处理,这里主要分析 GET/POST/HEADER/ 等注解
GET
else if (annotation instanceof GET) {
parseHttpMethodAndPath(“GET”, ((GET) annotation).value(), false);
}
get 类型的请求,没有请求体
private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
// 如果该 Builder 已经有 HTTPMethod 了就不能改变了,直接抛异常
if (this.httpMethod != null) {
throw methodError(“Only one HTTP method is allowed. Found: %s and %s.”,
this.httpMethod, httpMethod);
}
// 将 HTTPMethod 赋值给 httpMethod 对象,Get、Post、Delete 等
this.httpMethod = httpMethod;
this.hasBody = hasBody;// 是否有请求体
// 如果 value 为 null,返回,因为 value 参数的值其实就是 relativeURL。所以不能为 null
if (value.isEmpty()) {
return;
}
// Get the relative URL path and existing query string, if present.
int question = value.indexOf(‘?’);
if (question != -1 && question < value.length() – 1) {
// Ensure the query string does not have any named parameters.
String queryParams = value.substring(question + 1);
// 获取查询参数
Matcher queryParamMatcher = PARAM_URL_REGEX.matcher(queryParams);
if (queryParamMatcher.find()) {
// 如果在 value 里面找到里查询参数的话,抛出异常。因为查询参数可以使用 @Query 注解来动态配置。
throw methodError(“URL query string \”%s\” must not have replace block. ”
+ “For dynamic query parameters use @Query.”, queryParams);
}
}
this.relativeUrl = value; // 将 value 赋值给 relativeUrl
this.relativeUrlParamNames = parsePathParameters(value); // 获取 value 里面的 path 占位符,如果有的话
}
再来看下解析 value 里的 path 占位符的方法。
/**
获取已知 URI 里面的路径集合,如果一个参数被使用了两次,它只会在 set 中出现一次,好拗口啊,使用 LinkedHashSet 来保存 path 参数集合,保证了路径参数的顺序。
* Gets the set of unique path parameters used in the given URI. If a parameter is used twice
* in the URI, it will only show up once in the set.
*/
static Set<String> parsePathParameters(String path) {
Matcher m = PARAM_URL_REGEX.matcher(path);
Set<String> patterns = new LinkedHashSet<>();
while (m.find()) {
patterns.add(m.group(1));
}
return patterns;
}
至此,GET 方法的相关的注解分析完毕
POST
else if (annotation instanceof POST) {
parseHttpMethodAndPath(“POST”, ((POST) annotation).value(), true);
}
POST 类型的请求,没有请求体。所以 hasBody 参数为 true。
parseHttpMethodAndPath() 方法已将在 GET 方法里面分析过了,这里面都一样。
其他的请求类型也是大同小异。
然后接着分析方法的 Header 注解
Headers
else if (annotation instanceof retrofit2.http.Headers) {
// 首先获取 Headers 注解的值,是一个字符串数组。
String[] headersToParse = ((retrofit2.http.Headers) annotation).value();
如果 header 注解长度为 0,抛出异常,所以使用了 header 注解必须设置值,不能存在空的 header
if (headersToParse.length == 0) {
throw methodError(“@Headers annotation is empty.”);
}
处理 header 信息,我猜肯定是一个 map
headers = parseHeaders(headersToParse);
啊,居然不是,666. 因为 header 不是 KV 结构的数据类型,而是一个 key 可以对应多个值。理论上可以使用 Map<String,Set<String>> 表示。
private Headers parseHeaders(String[] headers) {
Headers.Builder builder = new Headers.Builder();
for (String header : headers) {
// header 以“:” 分割,前面是 key, 后面是 value
int colon = header.indexOf(‘:’);
if (colon == -1 || colon == 0 || colon == header.length() – 1) {
//header 必须是 key:value 格式表示,不然报错
throw methodError(
“@Headers value must be in the form \”Name: Value\”. Found: \”%s\””, header);
}
String headerName = header.substring(0, colon); //key 值
String headerValue = header.substring(colon + 1).trim(); //value 值,必须是一个数组,艹,又猜错了。
if (“Content-Type”.equalsIgnoreCase(headerName)) {
// 遇到 ”Content-Type” 字段。还需要获得具体的 MediaType。
MediaType type = MediaType.parse(headerValue);
if (type == null) {
// 如果 mediaType 为 null。抛出一个 type 畸形的错误。
throw methodError(“Malformed content type: %s”, headerValue);
}
contentType = type;
} else {
将 header 的 key 和 value 加入到 Builder 里面。
builder.add(headerName, headerValue);
}
}
最后调用 build 方法生成一个 Header 对爱。
return builder.build();
}
/**
* Add a header with the specified name and value. Does validation of header names and values.
*/
public Builder add(String name, String value) {
checkNameAndValue(name, value);
return addLenient(name, value);
}
Builder addLenient(String name, String value) {
namesAndValues.add(name);
namesAndValues.add(value.trim());
return this;
}
final List<String> namesAndValues = new ArrayList<>(20);
namesAndValues 是 Header.Builder 类的一种子段。可见在 Builder 内部 header 信息是按照 key/value 异常放到一个 String 集合里面的。为什么不放到一个 Map 里面呢,不懂。
总之,最后就是讲方法的 Headers 注解信息提取完毕。
2:处理方法参数
int parameterCount = parameterAnnotationsArray.length; // 求得数组的长度
parameterHandlers = new ParameterHandler<?>[parameterCount];
for (int p = 0; p < parameterCount; p++) {
Type parameterType = parameterTypes[p]; // 便利参数,依次处理参数
// 如果参数不能解析,抛出异常
if (Utils.hasUnresolvableType(parameterType)) {
throw parameterError(p, “Parameter type must not include a type variable or wildcard: %s”,
parameterType);
}
// 获取第 p 个参数的注解数组,如果没有注解抛出异常,可见,使用了 Retrofit,接口方法中每个参数都必须使用注解进行修饰。
Annotation[] parameterAnnotations = parameterAnnotationsArray[p];
if (parameterAnnotations == null) {
throw parameterError(p, “No Retrofit annotation found.”);
}
// 解析方法中的参数,存入 parameterHandlers[] 数组中。
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
}
参数校验
Utils.hasUnresolvableType(parameterType),这个方法是对参数的类型做个校验。
static boolean hasUnresolvableType(Type type) {
// 如果参数是引用数据类型,返回 false,可见,接口定义中方法的参数只能是基本数据类型
if (type instanceof Class<?>) {
return false;
}
// 如果参数是泛型
if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// 去除泛型类中的实际类型,遍历
for (Type typeArgument : parameterizedType.getActualTypeArguments()) {
// 如果有一个泛型参数是基本数据类型,返回 true,都不是返回 false
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);
}
解析参数
parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations);
private ParameterHandler<?> parseParameter(
int p, Type parameterType, Annotation[] annotations) {
ParameterHandler<?> result = null;
// 遍历参数的注解数组,调用 parseParameterAnnotation()
for (Annotation annotation : annotations) {
ParameterHandler<?> annotationAction = parseParameterAnnotation(
p, parameterType, annotations, annotation);
// 如果该注解没有返回,则解析下一个注解
if (annotationAction == null) {
continue;
}
if (result != null) {
throw parameterError(p, “Multiple Retrofit annotations found, only one allowed.”);
}
result = annotationAction; // 将解析的结果赋值给 Result
}
// 如果注解为 null,抛出异常。这个地方永远不会调用,因为在获取注解数组之前就做过判断了,如果注解数组为 null,直接抛异常,Line197-Line200 in ServiceMethod.Builder 中
if (result == null) {
throw parameterError(p, “No Retrofit annotation found.”);
}
return result;
}
获取参数注解信息
再来看看 parseParameterAnnotation() 方法, 内容略多
private ParameterHandler<?> parseParameterAnnotation(
int p, Type type, Annotation[] annotations, Annotation annotation) {
if (annotation instanceof Url) {
// 如果使用了 Url 注解,
if (gotUrl) {
// 如果 gotUrl 为 true,因为 gotURL 默认为 false,说明之前处理过 Url 注解了, 抛出多个 @Url 注解异常
throw parameterError(p, “Multiple @Url method annotations found.”);
}
if (gotPath) {
// 如果 gotPath 为 true,抛出异常,说明 @Path 注解不能和 @Url 注解一起使用
throw parameterError(p, “@Path parameters may not be used with @Url.”);
}
if (gotQuery) {
// 如果 gotQuery 为 true,抛出异常,说明 @Url 注解不能用在 @Query 注解后面
throw parameterError(p, “A @Url parameter must not come after a @Query”);
}
if (relativeUrl != null) {
// 如果 relativeUrl 不为 null, 抛出异常,说明使用了 @Url 注解,relativeUrl 必须为 null
throw parameterError(p, “@Url cannot be used with @%s URL”, httpMethod);
}
gotUrl = true;
—————————————————————————————-
// 如果参数类型是 HttpURL,String,URI 或者参数类型是“android.net.Uri”, 返回 ParameterHandler.RelativeUrl(),实际是交由这个类处理
if (type == HttpUrl.class
|| type == String.class
|| type == URI.class
|| (type instanceof Class && “android.net.Uri”.equals(((Class<?>) type).getName()))) {
return new ParameterHandler.RelativeUrl();
} else {
// 不然就抛出异常,也就是说 @Url 注解必须使用在 okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri 这几种类型的参数上。
throw parameterError(p,
“@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.”);
}
——————————————————————————————
} else if (annotation instanceof Path) {//@Path 注解
// 如果 gotQuery 为 true。抛出异常,因为 @Path 修饰的参数是路径的占位符。不是查询参数,不能使用 @Query 注解修饰
if (gotQuery) {
throw parameterError(p, “A @Path parameter must not come after a @Query.”);
}
if (gotUrl) {
throw parameterError(p, “@Path parameters may not be used with @Url.”);
}
// 如果相对路径为 null,那 @path 注解也就无意义了。
if (relativeUrl == null) {
throw parameterError(p, “@Path can only be used with relative url on @%s”, httpMethod);
}
gotPath = true;
Path path = (Path) annotation;
String name = path.value(); // 获取 @Path 注解的值
validatePathName(p, name); // 对改值进行校验,1 该 value 必须是合法字符,2: 该相对路径必须包含相应的占位符
// 然后将改参数的所有注解进行处理,最终调用 ParameterHandler.Path 进行处理。
Converter<?, String> converter = retrofit.stringConverter(type, annotations);
return new ParameterHandler.Path<>(name, converter, path.encoded());
} else if (annotation instanceof Query) {//Query 注解,看不太懂,最后也是调用 ParameterHandler.Query 进行处理
Query query = (Query) annotation;
String name = query.value();
boolean encoded = query.encoded();
Class<?> rawParameterType = Utils.getRawType(type);
gotQuery = true;
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ ” must include generic type (e.g., ”
+ rawParameterType.getSimpleName()
+ “<String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Query<>(name, converter, encoded).array();
} else {
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Query<>(name, converter, encoded);
}
} else if (annotation instanceof QueryMap) {
Class<?> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, “@QueryMap parameter type must be Map.”);
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, “Map must include generic types (e.g., Map<String, String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, “@QueryMap keys must be of type String: ” + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.QueryMap<>(valueConverter, ((QueryMap) annotation).encoded());
} else if (annotation instanceof Header) {
Header header = (Header) annotation;
String name = header.value();
Class<?> rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ ” must include generic type (e.g., ”
+ rawParameterType.getSimpleName()
+ “<String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Header<>(name, converter).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Header<>(name, converter).array();
} else {
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Header<>(name, converter);
}
} else if (annotation instanceof HeaderMap) {
Class<?> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, “@HeaderMap parameter type must be Map.”);
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, “Map must include generic types (e.g., Map<String, String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, “@HeaderMap keys must be of type String: ” + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
return new ParameterHandler.HeaderMap<>(valueConverter);
} else if (annotation instanceof Field) {
if (!isFormEncoded) {
throw parameterError(p, “@Field parameters can only be used with form encoding.”);
}
Field field = (Field) annotation;
String name = field.value();
boolean encoded = field.encoded();
gotField = true;
Class<?> rawParameterType = Utils.getRawType(type);
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ ” must include generic type (e.g., ”
+ rawParameterType.getSimpleName()
+ “<String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
Converter<?, String> converter =
retrofit.stringConverter(iterableType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
Converter<?, String> converter =
retrofit.stringConverter(arrayComponentType, annotations);
return new ParameterHandler.Field<>(name, converter, encoded).array();
} else {
Converter<?, String> converter =
retrofit.stringConverter(type, annotations);
return new ParameterHandler.Field<>(name, converter, encoded);
}
} else if (annotation instanceof FieldMap) {
if (!isFormEncoded) {
throw parameterError(p, “@FieldMap parameters can only be used with form encoding.”);
}
Class<?> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, “@FieldMap parameter type must be Map.”);
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p,
“Map must include generic types (e.g., Map<String, String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, “@FieldMap keys must be of type String: ” + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
Converter<?, String> valueConverter =
retrofit.stringConverter(valueType, annotations);
gotField = true;
return new ParameterHandler.FieldMap<>(valueConverter, ((FieldMap) annotation).encoded());
} else if (annotation instanceof Part) {
if (!isMultipart) {
throw parameterError(p, “@Part parameters can only be used with multipart encoding.”);
}
Part part = (Part) annotation;
gotPart = true;
String partName = part.value();
Class<?> rawParameterType = Utils.getRawType(type);
if (partName.isEmpty()) {
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ ” must include generic type (e.g., ”
+ rawParameterType.getSimpleName()
+ “<String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (!MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
throw parameterError(p,
“@Part annotation must supply a name or use MultipartBody.Part parameter type.”);
}
return ParameterHandler.RawPart.INSTANCE.iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = rawParameterType.getComponentType();
if (!MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
throw parameterError(p,
“@Part annotation must supply a name or use MultipartBody.Part parameter type.”);
}
return ParameterHandler.RawPart.INSTANCE.array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
return ParameterHandler.RawPart.INSTANCE;
} else {
throw parameterError(p,
“@Part annotation must supply a name or use MultipartBody.Part parameter type.”);
}
} else {
Headers headers =
Headers.of(“Content-Disposition”, “form-data; name=\”” + partName + “\””,
“Content-Transfer-Encoding”, part.encoding());
if (Iterable.class.isAssignableFrom(rawParameterType)) {
if (!(type instanceof ParameterizedType)) {
throw parameterError(p, rawParameterType.getSimpleName()
+ ” must include generic type (e.g., ”
+ rawParameterType.getSimpleName()
+ “<String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) type;
Type iterableType = Utils.getParameterUpperBound(0, parameterizedType);
if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(iterableType))) {
throw parameterError(p, “@Part parameters using the MultipartBody.Part must not ”
+ “include a part name in the annotation.”);
}
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(iterableType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter).iterable();
} else if (rawParameterType.isArray()) {
Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
if (MultipartBody.Part.class.isAssignableFrom(arrayComponentType)) {
throw parameterError(p, “@Part parameters using the MultipartBody.Part must not ”
+ “include a part name in the annotation.”);
}
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(arrayComponentType, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter).array();
} else if (MultipartBody.Part.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, “@Part parameters using the MultipartBody.Part must not ”
+ “include a part name in the annotation.”);
} else {
Converter<?, RequestBody> converter =
retrofit.requestBodyConverter(type, annotations, methodAnnotations);
return new ParameterHandler.Part<>(headers, converter);
}
}
} else if (annotation instanceof PartMap) {
if (!isMultipart) {
throw parameterError(p, “@PartMap parameters can only be used with multipart encoding.”);
}
gotPart = true;
Class<?> rawParameterType = Utils.getRawType(type);
if (!Map.class.isAssignableFrom(rawParameterType)) {
throw parameterError(p, “@PartMap parameter type must be Map.”);
}
Type mapType = Utils.getSupertype(type, rawParameterType, Map.class);
if (!(mapType instanceof ParameterizedType)) {
throw parameterError(p, “Map must include generic types (e.g., Map<String, String>)”);
}
ParameterizedType parameterizedType = (ParameterizedType) mapType;
Type keyType = Utils.getParameterUpperBound(0, parameterizedType);
if (String.class != keyType) {
throw parameterError(p, “@PartMap keys must be of type String: ” + keyType);
}
Type valueType = Utils.getParameterUpperBound(1, parameterizedType);
if (MultipartBody.Part.class.isAssignableFrom(Utils.getRawType(valueType))) {
throw parameterError(p, “@PartMap values cannot be MultipartBody.Part. ”
+ “Use @Part List<Part> or a different value type instead.”);
}
Converter<?, RequestBody> valueConverter =
retrofit.requestBodyConverter(valueType, annotations, methodAnnotations);
PartMap partMap = (PartMap) annotation;
return new ParameterHandler.PartMap<>(valueConverter, partMap.encoding());
} else if (annotation instanceof Body) {
if (isFormEncoded || isMultipart) {
throw parameterError(p,
“@Body parameters cannot be used with form or multi-part encoding.”);
}
if (gotBody) {
throw parameterError(p, “Multiple @Body method annotations found.”);
}
Converter<?, RequestBody> converter;
try {
converter = retrofit.requestBodyConverter(type, annotations, methodAnnotations);
} catch (RuntimeException e) {
// Wide exception range because factories are user code.
throw parameterError(e, p, “Unable to create @Body converter for %s”, type);
}
gotBody = true;
return new ParameterHandler.Body<>(converter);
}
return null; // Not a Retrofit annotation. 找不到该注解
}
从上面可以看出,改立参数注解的套路就是:先判断该注解的类型,然后使用策略模式分别调用 ParameterHandler 里对应的子类来处理