Retrofit原理(四):返回值的参数是怎么获取到的?

前面说了,rentrunType和responseType都是通过反射拿到的,但是范型在编译的时候不是会被擦除吗?那又是怎么拿到具体的类型的?

abstract class ServiceMethod<T> {
  static <T> ServiceMethod<T> parseAnnotations(Retrofit retrofit, Method method) {
    RequestFactory requestFactory = RequestFactory.parseAnnotations(retrofit, 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.");
    }

    return HttpServiceMethod.parseAnnotations(retrofit, method, requestFactory);
  }

  abstract @Nullable T invoke(Object[] args);
}

在进入DefaultCallAdapterFactory里看看

@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<Foo> or Call<? extends Foo>");
    }
    //这里根据returnType获取到里面的参数化类型的type
    final Type responseType = Utils.getParameterUpperBound(0, (ParameterizedType) returnType);

    final Executor executor = Utils.isAnnotationPresent(annotations, SkipCallbackExecutor.class)
        ? null
        : callbackExecutor;

    return new CallAdapter<Object, Call<?>>() {
      @Override public Type responseType() {
        return responseType;
      }

      @Override public Call<Object> adapt(Call<Object> call) {
        return executor == null
            ? call
            : new ExecutorCallbackCall<>(executor, call);
      }
    };
  }

好,再回到获取returnType的那一行Type returnType = method.getGenericReturnType();

    public Type getGenericReturnType() {
    //如果有签名信息,则根据签名信息获取
      if (getGenericSignature() != null) {
        return getGenericInfo().getReturnType();
      } else { return getReturnType();}
    }

这个签名信息实质上是编译成字节码后jvm加上的,看下面的例子

public class Test {

    public static void main(String[] args) {
        test();
    }

    public static List<Map<String, Integer>> test(){
        System.out.println("hello!");
        return null;
    }

}

来查看test的字节码,看到那个signature后面附带的信息没,所指的便是这个

  // access flags 0x9
  // signature ()Ljava/util/List<Ljava/util/Map<Ljava/lang/String;Ljava/lang/Integer;>;>;
  // declaration: java.util.List<java.util.Map<java.lang.String, java.lang.Integer>> test()
  public static test()Ljava/util/List;
   L0
    LINENUMBER 13 L0
    GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
    LDC "hello!"
    INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
   L1
    LINENUMBER 14 L1
    ACONST_NULL
    ARETURN
    MAXSTACK = 2
    MAXLOCALS = 0

下面来看个示例

	public static void main(String[] args) throws NoSuchMethodException, NoSuchFieldException, IllegalAccessException {
        test();
        //获取Test类中的test方法
        Method method = Test.class.getDeclaredMethod("test");
        //获取返回值类型
        Type type = method.getGenericReturnType();
        //通过递归取出来
        checkType(type);
		
		//由于没有传入参数,下面先注释掉
        /*for (Type genericParamType : method.getGenericParameterTypes()) {
            checkType(genericParamType);
        }*/
		//这里获取signature字段
        Field signature = Method.class.getDeclaredField("signature");
        signature.setAccessible(true);
        System.out.println("signature : " + signature.get(method));
    }

    public static List<Map<String, Integer>> test(){
        System.out.println("hello!");
        return null;
    }
    public static void checkType(Type type) {
    //如果是参数化类型
        if (type instanceof ParameterizedType) {
            System.out.println("ParameterizedType : " + type);
            for (Type type1 : ((ParameterizedType) type).getActualTypeArguments()) {
                checkType(type1);
            }
        } else {
            System.out.println("Type : " + type);
        }
    }

输出为

hello!
ParameterizedType : java.util.List<java.util.Map<java.lang.String, java.lang.Integer>>
ParameterizedType : java.util.Map<java.lang.String, java.lang.Integer>
Type : class java.lang.String
Type : class java.lang.Integer
signature : ()Ljava/util/List<Ljava/util/Map<Ljava/lang/String;Ljava/lang/Integer;>;>;

当然这个方法也是有限制的,首先是signature 不能去掉,一般也是在混淆的时候会去掉,所得保留即可。

发布了38 篇原创文章 · 获赞 6 · 访问量 3403

猜你喜欢

转载自blog.csdn.net/qq_37704124/article/details/100047711