美文网首页
retrofit源码解析(二)

retrofit源码解析(二)

作者: Fargo的狗窝 | 来源:发表于2017-09-30 14:25 被阅读0次

    接着上一篇的内容接着讲
    上一篇我们说到了retrofit的初始化
    这一篇我们将讲述retrofit的调用过程

    public interface GitHubService {
     @GET("users/{user}/repos")
     Call<List<Repo>> listRepos(@Path("user") String user);
    }
    
     Retrofit retrofit = new Retrofit.Builder()
       .baseUrl("https://api.github.com/")
       .build();
    GitHubService service = retrofit.create(GitHubService.class);
    

    接下来就是讲讲retrofit.create(class);

    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, @Nullable 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<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
      }
    

    我们看下第一行代码

    Utils.validateServiceInterface(service);
    
    
    //Utils.java
    static <T> void validateServiceInterface(Class<T> service) {
        if (!service.isInterface()) {
          throw new IllegalArgumentException("API declarations must be interfaces.");
        }
        // Prevent API interfaces from extending other interfaces. This not only avoids a bug in
        // Android (http://b.android.com/58753) but it forces composition of API declarations which is
        // the recommended pattern.
        if (service.getInterfaces().length > 0) {
          throw new IllegalArgumentException("API interfaces must not extend other interfaces.");
        }
      }
    

    如果Service不是接口或者Service继承了其他接口会抛出IllegalArgumentException异常
    好啦再看看

    if (validateEagerly) {
          eagerlyValidateMethods(service);
        }
    

    我找了两圈,没发现初始化validateEagerly的,所以validateEagerly应该是默认值false;看注释貌似是控制预加载注解的,也就是说默认不加载,等到调用时才加载,那么我们先略过预加载,等后面看到加载的时候再搞一搞

    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, @Nullable 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<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            });
    

    create 方法return了一个动态代理对象,什么是动态代理?自行百度,这里不讲。
    我们知道 调用动态代理对象的时候,都会被InvocationHandler拦截,最后执行InvocationHandler invoke()方法;
    也就是说下面这段代码

    public interface GitHubService {
     @GET("users/{user}/repos")
     Call<List<Repo>> listRepos(@Path("user") String user);
    }
    
     Retrofit retrofit = new Retrofit.Builder()
       .baseUrl("https://api.github.com/")
       .build();
    GitHubService service = retrofit.create(GitHubService.class);
    
    

    当调用retrofit.create(GitHubService.class)时,会生成一个GitHubService的对象,而调用生成的GitHubService对象的每个方法时,都会调用到InvocationHandler. invoke(),
    那么我们来看看这个invoke()方法

    new InvocationHandler() {
              private final Platform platform = Platform.get();
    
              @Override public Object invoke(Object proxy, Method method, @Nullable 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<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
              }
            }
    

    当调用的method属于Object时,执行method.invoke(this, args);,也即是原来object的操作并return
    当调用的method是默认方法时,执行默认方法调用,并return;
    当调用的method属于Object也不是默认方法时,执行

     ServiceMethod<Object, Object> serviceMethod =
                    (ServiceMethod<Object, Object>) loadServiceMethod(method);
                OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
    

    接下来我们看看loadServiceMethod()的实现

    ServiceMethod<?, ?> loadServiceMethod(Method method) {
        ServiceMethod<?, ?> result = serviceMethodCache.get(method);
        if (result != null) return result;
    
        synchronized (serviceMethodCache) {
          result = serviceMethodCache.get(method);
          if (result == null) {
            result = new ServiceMethod.Builder<>(this, method).build();
            serviceMethodCache.put(method, result);
          }
        }
        return result;
      }
    

    serviceMethodCache是一个ServiceMethod缓存,以method为key的一个map,当serviceMethodCache中存在对应key的ServiceMethod则return,不存在则通过ServiceMethod. Builder生成一个,并put到cache里,再return,
    我们看看
    ServiceMethod.Builder()的代码

    Builder(Retrofit retrofit, Method method) {
          this.retrofit = retrofit;
          this.method = method;
          //方法的注解
          this.methodAnnotations = method.getAnnotations();
          //方法参数类型
          this.parameterTypes = method.getGenericParameterTypes();
          //方法参数注解
          this.parameterAnnotationsArray = method.getParameterAnnotations();
        }
    
    
    
    public ServiceMethod build() {
    //创建一个CallAdapter
          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();
    
          for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
          }
    
          if (httpMethod == null) {
            throw methodError("HTTP method annotation is required (e.g., @GET, @POST, etc.).");
          }
    
          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).");
            }
          }
    
          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);
          }
    
          if (relativeUrl == null && !gotUrl) {
            throw methodError("Missing either @%s URL or @Url parameter.", httpMethod);
          }
          if (!isFormEncoded && !isMultipart && !hasBody && gotBody) {
            throw methodError("Non-body HTTP method cannot contain @Body.");
          }
          if (isFormEncoded && !gotField) {
            throw methodError("Form-encoded method must contain at least one @Field.");
          }
          if (isMultipart && !gotPart) {
            throw methodError("Multipart method must contain at least one @Part.");
          }
    
          return new ServiceMethod<>(this);
        }
    
        private CallAdapter<T, R> createCallAdapter() {
    //被调用方法返回值类型
          Type returnType = method.getGenericReturnType();
    //当返回值类型为无法解析类型时
          if (Utils.hasUnresolvableType(returnType)) {
            throw methodError(
                "Method return type must not include a type variable or wildcard: %s", returnType);
          }
    //当返回值类型为void时
          if (returnType == void.class) {
            throw methodError("Service methods cannot return void.");
          }
    //获取方法的注解列表
          Annotation[] annotations = method.getAnnotations();
          try {
            //noinspection unchecked
    //最终调用了 retrofit.callAdapte方法
            return (CallAdapter<T, R>) retrofit.callAdapter(returnType, annotations);
          } catch (RuntimeException e) { // Wide exception range because factories are user code.
            throw methodError(e, "Unable to create call adapter for %s", returnType);
          }
        }
    

    在build中可以看到首先create一个CallAdapter,我们之前知道,这个callAdapter的目的是将,将CallAdapter<T, R>R类型转换为T类型(如,rxjavaAdapter,将call<T>转换为Observable<T>)
    那么继续让我们看 retrofit.callAdapte()方法

    
    public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
        return nextCallAdapter(null, returnType, annotations);
      }
    
      /**
       * Returns the {@link CallAdapter} for {@code returnType} from the available {@linkplain
       * #callAdapterFactories() factories} except {@code skipPast}.
       *
       * @throws IllegalArgumentException if no call adapter available for {@code type}.
       */
      public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
          Annotation[] annotations) {
        checkNotNull(returnType, "returnType == null");
        checkNotNull(annotations, "annotations == null");
    
        int start = adapterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = adapterFactories.size(); i < count; i++) {
          CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
          if (adapter != null) {
            return adapter;
          }
        }
    

    那么adapterFactories这个是什么?还记得之前说过,如果没有设置adapterFactorie,默认使用platform.defaultCallAdapterFactory()嘛?(Retrofit.Builder.build()方法中),我们之前也说过android 的默认CallAdapterFactory是ExecutorCallAdapterFactory;
    那么让我们看看ExecutorCallAdapterFactory的get方法

    @Override
      public CallAdapter<?, ?> get(Type returnType, Annotation[] annotations, Retrofit retrofit) {
        if (getRawType(returnType) != Call.class) {
          return null;
        }
        final Type responseType = Utils.getCallResponseType(returnType);
        return new CallAdapter<Object, Call<?>>() {
          @Override public Type responseType() {
            return responseType;
          }
    
          @Override public Call<Object> adapt(Call<Object> call) {
            return new ExecutorCallbackCall<>(callbackExecutor, call);
          }
        };
      }
    

    之前也说过,ExecutorCallAdapterFactory只处理返回值为Call<?>的其他返回null,结合nextCallAdapter函数,可以看出,遍历找到一个不为null的,也即是找到一个处理Call的adapter,如果他是Observable<?>类型的,那么
    ExecutorCallAdapterFactory就没办法处理,这个时候就得RxjavaAdapterFactory出马,

    我们接着看build方法的代码

    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?");
          }
    

    如果call的泛型类型是Retrofit.Response或者okhttp3.Response
    抛出一个异常

     responseConverter = createResponseConverter();
    

    接下来看下

    private Converter<ResponseBody, T> createResponseConverter() {
          Annotation[] annotations = method.getAnnotations();
          try {
            return retrofit.responseBodyConverter(responseType, annotations);
          } catch (RuntimeException e) { // Wide exception range because factories are user code.
            throw methodError(e, "Unable to create converter for %s", responseType);
          }
        }
    

    没错,又跳到retrofit类里了,((⊙﹏⊙)b,写文章的时候跳来跳去累死了)
    让我们继续看看responseBodyConverter的代码

    
    /**
       * Returns a {@link Converter} for {@link ResponseBody} to {@code type} from the available
       * {@linkplain #converterFactories() factories}.
       *
       * @throws IllegalArgumentException if no converter available for {@code type}.
       */
      public <T> Converter<ResponseBody, T> responseBodyConverter(Type type, Annotation[] annotations) {
        return nextResponseBodyConverter(null, type, annotations);
      }
    
      /**
       * Returns a {@link Converter} for {@link ResponseBody} to {@code type} from the available
       * {@linkplain #converterFactories() factories} except {@code skipPast}.
       *
       * @throws IllegalArgumentException if no converter available for {@code type}.
       */
      public <T> Converter<ResponseBody, T> nextResponseBodyConverter(
          @Nullable Converter.Factory skipPast, Type type, Annotation[] annotations) {
        checkNotNull(type, "type == null");
        checkNotNull(annotations, "annotations == null");
    
        int start = converterFactories.indexOf(skipPast) + 1;
        for (int i = start, count = converterFactories.size(); i < count; i++) {
          Converter<ResponseBody, ?> converter =
              converterFactories.get(i).responseBodyConverter(type, annotations, this);
          if (converter != null) {
            //noinspection unchecked
            return (Converter<ResponseBody, T>) converter;
          }
        }
    
        StringBuilder builder = new StringBuilder("Could not locate ResponseBody converter for ")
            .append(type)
            .append(".\n");
        if (skipPast != null) {
          builder.append("  Skipped:");
          for (int i = 0; i < start; i++) {
            builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
          }
          builder.append('\n');
        }
        builder.append("  Tried:");
        for (int i = start, count = converterFactories.size(); i < count; i++) {
          builder.append("\n   * ").append(converterFactories.get(i).getClass().getName());
        }
        throw new IllegalArgumentException(builder.toString());
      }
    
    

    调用nextResponseBodyConverter时 Converter.Factory传的是null所以start=0;还记得在我们new 一个Retrofit.Builder的时候,add进去的BuiltInConverters嘛?我们之前说过BuiltInConverters只能处理requestBody,和ResponseBody,其他返回为null,所以Call<ResponseBody>/Observable<ResponseBody>或者Call<requestBody>/Observable<requestBody> 就会匹配到BuiltInConverters,由BuiltInConverters处理,那么问题来了,如果我想处理Call<String>呢?emmmmm..你得自定义一个Converter.Factory,将Response body转换成String或者其他对象,(例如GsonConverterFactory)

    继续看build()代码

    for (Annotation annotation : methodAnnotations) {
            parseMethodAnnotation(annotation);
          }
    
    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) {
            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) {
            if (isFormEncoded) {
              throw methodError("Only one encoding annotation is allowed.");
            }
            isMultipart = true;
          } else if (annotation instanceof FormUrlEncoded) {
            if (isMultipart) {
              throw methodError("Only one encoding annotation is allowed.");
            }
            isFormEncoded = true;
          }
        }
    
        private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
          if (this.httpMethod != null) {
            throw methodError("Only one HTTP method is allowed. Found: %s and %s.",
                this.httpMethod, httpMethod);
          }
          this.httpMethod = httpMethod;
          this.hasBody = hasBody;
    
          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()) {
              throw methodError("URL query string \"%s\" must not have replace block. "
                  + "For dynamic query parameters use @Query.", queryParams);
            }
          }
    
          this.relativeUrl = value;
          this.relativeUrlParamNames = parsePathParameters(value);
        }
    

    这里的代码略多,我们用get来举例子,其余原理类似

    parseHttpMethodAndPath("GET", ((GET) annotation).value(), false);
    
      private void parseHttpMethodAndPath(String httpMethod, String value, boolean hasBody) {
         ···
          ···
          ···
          this.relativeUrl = value;
          this.relativeUrlParamNames = parsePathParameters(value);
        }
    
    
      /**
       * 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("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
    最终会调到parsePathParameters,并且将所有{?}的参数名用正则表达式找出来,并且保存在ServiceMethod.relativeUrlParamNames中

    我们继续看ServiceMethod.Builder.build()代码

    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);
          }
    

    parameterAnnotationsArray是参数注解数组,参数有注解的最后都调用了parseParameter(),

     private ParameterHandler<?> parseParameter(
            int p, Type parameterType, Annotation[] annotations) {
          ParameterHandler<?> result = null;
          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;
          }
    
          if (result == null) {
            throw parameterError(p, "No Retrofit annotation found.");
          }
    
          return result;
        }
    
      private ParameterHandler<?> parseParameterAnnotation(
            int p, Type type, Annotation[] annotations, Annotation annotation) {
          if (annotation instanceof Url) {
            if (gotUrl) {
              throw parameterError(p, "Multiple @Url method annotations found.");
            }
            if (gotPath) {
              throw parameterError(p, "@Path parameters may not be used with @Url.");
            }
            if (gotQuery) {
              throw parameterError(p, "A @Url parameter must not come after a @Query");
            }
            if (relativeUrl != null) {
              throw parameterError(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();
            } else {
              throw parameterError(p,
                  "@Url must be okhttp3.HttpUrl, String, java.net.URI, or android.net.Uri type.");
            }
    
          } else if (annotation instanceof Path) {
            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.");
            }
            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();
            validatePathName(p, name);
    
            Converter<?, String> converter = retrofit.stringConverter(type, annotations);
            return new ParameterHandler.Path<>(name, converter, path.encoded());
    
          } else if (annotation instanceof 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 QueryName) {
            QueryName query = (QueryName) annotation;
            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.QueryName<>(converter, encoded).iterable();
            } else if (rawParameterType.isArray()) {
              Class<?> arrayComponentType = boxIfPrimitive(rawParameterType.getComponentType());
              Converter<?, String> converter =
                  retrofit.stringConverter(arrayComponentType, annotations);
              return new ParameterHandler.QueryName<>(converter, encoded).array();
            } else {
              Converter<?, String> converter =
                  retrofit.stringConverter(type, annotations);
              return new ParameterHandler.QueryName<>(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.
        }
    

    还是拿官网例子

    @GET("users/{user}/repos")
     Call<List<Repo>> listRepos(@Path("user") String user);
    

    @Path("user") String user
    parseParameterAnnotation()调用的时候,annotation isinstanceof Path
    前面三个判断变量初始值为false,最终执行的是以下代码

    gotPath = true;
    
            Path path = (Path) annotation;
            String name = path.value();
            validatePathName(p, name);
    
            Converter<?, String> converter = retrofit.stringConverter(type, annotations);
            return new ParameterHandler.Path<>(name, converter, path.encoded());
    

    我们来看下retrofit.stringConverter

    public <T> Converter<T, String> stringConverter(Type type, Annotation[] annotations) {
        checkNotNull(type, "type == null");
        checkNotNull(annotations, "annotations == null");
    
        for (int i = 0, count = converterFactories.size(); i < count; i++) {
          Converter<?, String> converter =
              converterFactories.get(i).stringConverter(type, annotations, this);
          if (converter != null) {
            //noinspection unchecked
            return (Converter<T, String>) converter;
          }
        }
    
        // Nothing matched. Resort to default converter which just calls toString().
        //noinspection unchecked
        return (Converter<T, String>) BuiltInConverters.ToStringConverter.INSTANCE;
      }
    

    这里我们可以看出,如果找不到stringConverter,则调用BuiltInConverters.ToStringConverter,

    static final class ToStringConverter implements Converter<Object, String> {
        static final ToStringConverter INSTANCE = new ToStringConverter();
    
        @Override public String convert(Object value) {
          return value.toString();
        }
      }
    

    ToStringConverter的代码很简单就是讲Object 转换为String,从这里我们就明白了,

    @GET("users/{user}/repos")
    Call<List<Repo>> listRepos(@Path("user") String user);
    的user是可以是任意类型的,只要重写它的tostring方法即可
    ok,回归主线,parseParameterAnnotation()调用之后,将@Path解析成
    new ParameterHandler.Path

    static final class Path<T> extends ParameterHandler<T> {
        private final String name;
        private final Converter<T, String> valueConverter;
        private final boolean encoded;
    
        Path(String name, Converter<T, String> valueConverter, boolean encoded) {
          this.name = checkNotNull(name, "name == null");
          this.valueConverter = valueConverter;
          this.encoded = encoded;
        }
    
        @Override void apply(RequestBuilder builder, @Nullable T value) throws IOException {
          if (value == null) {
            throw new IllegalArgumentException(
                "Path parameter \"" + name + "\" value must not be null.");
          }
          builder.addPathParam(name, valueConverter.convert(value), encoded);
        }
      }
    
    //RequestBuilder.java
    void addPathParam(String name, String value, boolean encoded) {
        if (relativeUrl == null) {
          // The relative URL is cleared when the first query parameter is set.
          throw new AssertionError();
        }
        relativeUrl = relativeUrl.replace("{" + name + "}", canonicalizeForPath(value, encoded));
      }
    

    最后,参数解析所有的信息都放入到了全局数据parameterHandlers中,每个parameterHandlers[i]都包含了各个参数的所有注解解析信息。
    至此return 一个ServiceMethod

    接下来我们回归InvocationHandler. invoke(),

     OkHttpCall<Object> okHttpCall = new OkHttpCall<>(serviceMethod, args);
                return serviceMethod.callAdapter.adapt(okHttpCall);
    
    

    我们来看看,OkHttpCall的源码...O__O "…额okhttpCall就是Call的代理类,负责处理http请求,好像没什么好讲,我就不讲了,本文到此结束

    相关文章

      网友评论

          本文标题:retrofit源码解析(二)

          本文链接:https://www.haomeiwen.com/subject/dmrbextx.html