Retrofit の注釈とインターフェイス メソッドの注釈をカスタマイズする方法


インターフェースメソッドとメソッドパラメータのアノテーション

Retrofitフレームワークの最大の機能の 1 つは、HTTP リクエストを記述するためにアノテーションを使用することです。

  • URLパラメータ置換およびクエリパラメータのサポート
  • オブジェクトをリクエストボディに変換します(JSON、プロトコルバッファなど)。
  • マルチパートのリクエスト本文とファイルのアップロード

アノテーションはメソッド アノテーションとメソッド パラメータ アノテーションに分けられ、リクエストがどのように処理されるかをマークします。

1. メソッドのアノテーション

1.1 アノテーションはリクエストメソッドを説明します

注釈名 意味を表現する
@得る GETリクエスト
@役職 POSTリクエスト
@消去 削除リクエスト
@頭 HEADリクエスト
@オプション オプションリクエスト
@パッチ パッチリクエスト

1. 注意事項@GET

    @GET("/users/query/all")
    Call<List<User>> getUsers();

2. コメント@POST:

    @POST("/users/query")
    @FormUrlEncoded
    Call<User> getUser(@Field("id") String id);

1.2 アノテーションはリクエストのコンテンツタイプ、戻り結果、リクエストヘッダーを記述します。

注釈名 意味を表現する
@FormUrlEncoded このアノテーションは、メソッド アノテーション @POST およびパラメーター アノテーション @Field とともに使用され、リクエスト エンティティ (ボディ部分) のコンテンツが URL エンコードされてアップロードされ、リクエスト (POST) の Content-Type が「application/x-www-form-urlencoded」。つまり、要求されたパラメータは key1=value1&key2=value2… の形式でサーバーに送信され、パラメータは URL エンコードされます。
@マルチパート このアノテーションは、メソッド アノテーション @POST およびパラメーター アノテーション @Part とともに使用され、リクエスト エンティティ (ボディ部分) のコンテンツがフォームを使用してアップロードされ、リクエスト (POST) の Content-Type が「マルチパート」であることを示します。 /フォームデータ」。フォームを使用してアップロードされるデータは、プレーン テキスト、プレーン ファイル、またはテキスト + ファイルです。
@ストリーミング 返された結果 (ResponseBody) をストリーム (バイト) に変換します。
@ヘッダー フラグリクエストヘッダー。

1. 注意事項@FormUrlEncoded

POSTリクエスト、リクエストヘッダーContent-Type:application/x-www-form-urlencoded、リクエストエンティティを送信しますid=value

    @POST("/users/query")
    @FormUrlEncoded
    Call<User> getUser(@Field("id") String id);

2. 注意事項@Multipart

POSTリクエスト、リクエストヘッダーContent-Type: multipart/form-data、リクエストエンティティid=value、画像ファイルを送信します。

    @POST("/users/update")
    @Multipart
    Call<ResponseBody> updateUserPortrait(@Part("id") int id, @Part(value = "image", encoding = "8-bit") RequestBody image);

3. 注意事項@Streaming

    @GET("/users/download")
    @Streaming
    Call<ResponseBody> downloadUserFile(@Query("id") int id);

4. 注意事項@Headers

    @Headers("Cache-Control: max-age=640000")
    @GET("/users/download")
    @Streaming
    Call<ResponseBody> downloadUserFile(@Query("id") int id);

2. パラメータのアノテーション

注釈名 意味を表現する
@体 このアノテーションはメソッド アノテーション @POST または @PUT と一緒に使用され、フラグ パラメーターは POJO または RequestBody オブジェクトであり、最終的にパラメーター オブジェクトをリクエスト エンティティのコンテンツ (ボディ部分) に直接変換します。
@分野 このアノテーションは、メソッド アノテーション @POST および @FormUrlEncoded と一緒に使用され、パラメーターがキーと値のペアであること、つまりリクエスト エンティティ (本体部分) が key1=value1&key2=value2… または key の形式で渡されることを示します。 =値1&キー=値2…。
@フィールドマップ @Field アノテーションと同じですが、パラメーター オブジェクトが Map である点が異なります。
@ヘッダ flag パラメータはリクエストヘッダーです
@HeaderMap flag パラメータは、Map コレクションのリクエスト ヘッダーです。
@部 このアノテーションは、メソッド アノテーション @POST およびパラメータ アノテーション @Multipart と一緒に使用されます。
@PartMap @Part アノテーションと同じですが、パラメーター オブジェクトが Map であり、Map で受け入れられる型が <String, RequestBody> である点が異なります。
@道 flag パラメータはリクエスト パスを置き換えるために使用されます。
@Query フラグ パラメーター (@Query("key1") String value1) がリクエスト パス (?key1=value1) に追加されます。
@QueryMap @Query アノテーションと同じですが、パラメーター オブジェクトが Map コレクションであり、Map コレクションがキーと値のペアに変換される点が異なります。
@クエリ名 @Query アノテーションと似ていますが、パラメータ (@QueryName 文字列フィルター) がパス (?フィルター) に直接追加される点が異なります。
@鬼ごっこ flag パラメータは、このリクエストにタグを付けるために使用されます
@URL flag パラメータはリクエスト パスを置き換えるために使用され、baseUrl は無視されます。

1. 注意事項@Body:

    @POST("/users/upload")
    Call<ResponseBody> uploadUserLog(@Body RequestBody body);

    //创建RequestBody
    RequestBody body = RequestBody.create(MediaType.parse("Content-Type: application/json;charset=UTF-8"), "Your json log");
    UserService#uploadUserLog(body);

2. 注釈@Filed@FiledMap

@Filed:

   @POST("/users/query")
    @FormUrlEncoded
    Call<User> getUser(@Field("id") String id);

@FieldMap:

    @POST("/users/query")
    @FormUrlEncoded
    Call<User> getUser(@FieldMap Map<String, String> filedMap);


    Map<String,String> filedMap = new HashMap<>();
    filedMap.put("id", "123");
    filedMap.put("age", "25");
    UserService#getUser(filedMap);

2. 注釈@Header@HeaderMap

@Header:

    @POST("/users/query")
    @FormUrlEncoded
    Call<User> getUser(@Field("id") String id, @Header("Accept-Language") String lang);

@HeaderMap:

    @POST("/users/query")
    @FormUrlEncoded
    Call<User> getUser(@Field("id") String id, @HeaderMap Map<String, String> headerMap);


    Map<String,String> headerMap = new HashMap<>();
    headerMap.put("Accept-Charset", "utf-8");
    headerMap.put("Accept", "text/plain");
    UserService#getUser("123", headerMap);

2. 注釈@Part@PartMap

@Part:

    @POST("/users/update")
    @Multipart
    Call<ResponseBody> updateUserPortrait(@Part("id") int id, @Part(value = "image", encoding = "8-bit") RequestBody image);

@PartMap:

    @POST("/users/upload/feedback")
    @Multipart
    Call<ResponseBody> uploadUserFeedback( @Part("file") RequestBody file, @PartMap Map<String, RequestBody> params);


    Map<String, RequestBody> partMap = new HashMap<>();
    partMap.put("deviceInfo", RequestBody.create(MediaType.parse("text/plain"), "deviceInfo"));
    partMap.put("content", RequestBody.create(MediaType.parse("text/plain"), "content"));
    File file = new File("test.png");
    RequestBody requestBody = RequestBody.create(MultipartBody.FORM, file);
    UserService#uploadUserFeedback(requestBody, partMap);

3. 注意事項@Path:

    @GET("/users/{name}")
    Call<List<User>> getUserByName(@Path("name") String name);

4. 注釈@Query@QueryMap

@Query:

    @GET("/users/query/friends")
    Call<List<User>> getUserFriends(@Query("page") int page);

@QueryMap:

    @GET("/users/query/friends/filter")
    Call<List<User>> getUserFriends(@QueryMap Map<String, String> params);

     Map<String, String> queryMap = new HashMap<>();
     queryMap.put("age", "23");
     queryMap.put("sex", "male");
     UserService#.getUserFriends(queryMap);

5. コメント@QueryName:

    @GET("/users/query/friends/filter")
    Call<List<User>> getUserFriendsByFileter(@QueryName String filter);

6. 注意事項@Url:

    @GET("/users/config")
    Call<ResponseBody> getUserConfig(@Url String url);

注釈の解析プロセス

アノテーション解析はクラスServiceMethod内の静的内部クラスBuilderbuildメソッド内で行われ、parseMethodAnnotation(annotation)メソッドのアノテーションはメソッドの呼び出しで解決され、parseParameterパラメータのアノテーションはメソッドの呼び出しで解決されます。

特定の解析手順に関しては、まずRetrofitサービス インターフェイスを作成するために使用します。

        Retrofit retrofit = new Retrofit.Builder().baseUrl("https://api.example.com/").build();
        UserService service = retrofit.create(UserService.class);

サービス インターフェイスの作成ではJava 動的プロキシが使用されます。特にRetrofitクラス内のメソッドを確認してくださいcreate

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

以前のJava ダイナミック プロキシ Proxy.newProxyInstance()によれば対象インターフェイス (UserService) のメソッドが呼び出されたときにインターフェイスInvocationHandler内のコールバック メソッドが呼び出され、そのメソッドの戻り値が対象インターフェイスの戻り値になります ( UserService) メソッド。上の例のように:invokeinvoke@GET

    @GET("/users/query/all")
    Call<List<User>> getUsers();

    Call<List<User>> call =  service.getUsers();
    call.enqueue(callback);

UserService がgetUsers()メソッドを呼び出すと、invokeそのメソッドが実行され、 が返されますCall<List<User>>

invokeメソッドでは、まず、実行されたメソッドがObjectクラスで宣言されたメソッドであるかどうかを判断します。

            if (method.getDeclaringClass() == Object.class) {
              return method.invoke(this, args);
            }

などhashCode内部のメソッドequalsです。Object2 つ目は、実行されたメソッドがターゲット インターフェイス (UserService) で宣言されたデフォルト メソッドであるかどうかを判断することです (Java 8.0 以降、デフォルト メソッドはインターフェイスで宣言できます)。

            if (platform.isDefaultMethod(method)) {
              return platform.invokeDefaultMethod(method, service, proxy, args);
            }

Platform主な違いは Android か Java です。最後にServiceMethodOkHttpCallオブジェクトを作成し、CallAdapterオブジェクト内のadaptメソッドを通じて、対応するインターフェイス メソッドの戻り値を返します。

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

loadServiceMethodこのメソッドでは、まずmethod対応するオブジェクトがServiceMethod既に存在するかどうかを確認し、存在する場合はそれを直接返し、存在しない場合はオブジェクトを作成してキャッシュに置きます。

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

クラスServiceMethod内の静的内部クラスBuilderのコンストラクターはオブジェクトRetrofitを受け入れMethod、最後にbuild()メソッドを呼び出してServiceMethodオブジェクトを作成します。

    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 = createCallAdapter();
      responseType = callAdapter.responseType();
      
      ...省略部分代码
      
      responseConverter = createResponseConverter();

      for (Annotation annotation : methodAnnotations) {
        parseMethodAnnotation(annotation); //解析方法注解
      }

      ...省略部分代码

      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); //解析方法参数注解
      }

      ...省略部分代码

      return new ServiceMethod<>(this);
    }

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

parameterHandlers[p] = parseParameter(p, parameterType, parameterAnnotations)このメソッドは主にメソッド パラメーターのアノテーションを分析します。

    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) {
        ...省略部分代码

      } else if (annotation instanceof Path) {
        ...省略部分代码

      } else if (annotation instanceof QueryName) {
        ...省略部分代码
        
      } else if (annotation instanceof QueryMap) {
        ...省略部分代码
        
      } else if (annotation instanceof Header) {
        ...省略部分代码
       
      } else if (annotation instanceof HeaderMap) {
        ...省略部分代码
       
      } else if (annotation instanceof Field) {
        ...省略部分代码
         
      } else if (annotation instanceof FieldMap) {
        ...省略部分代码
        
      } else if (annotation instanceof Part) {
        ...省略部分代码
      
      } else if (annotation instanceof PartMap) {
        ...省略部分代码
        
      } else if (annotation instanceof Body) {
        ...省略部分代码
        
      }
    }

アノテーションの具体的な分析内容についてはここでは分析・紹介しませんので、興味があればこの部分のコードをじっくり読んでみてください。


インターフェースメソッドのアノテーションをカスタマイズする方法

カスタム インターフェイス メソッド アノテーションに関する重要な質問は、このメソッド アノテーションをいつどのように解析するかということです。

ServiceMethod上記のアノテーション解析処理から、クラス内の静的内部クラスBuilderbuildメソッド内でアノテーション解析が行われていることが分かります。buildメソッドのコードの最初の行をもう一度見てください。

    callAdapter = createCallAdapter(); //创建一个 CallAdapter 对象

createCallAdapter()メソッドはCallAdapter<T, R>オブジェクト。リクエスト結果のレスポンスタイプをカスタムタイプに変換するCallAdapter<R, T>機能を持つインターフェースですオブジェクトはクラスを通じて作成されます。これは、オブジェクトの作成時にメソッドによって追加されます。RTCallAdapterCallAdapter.FactoryRetrofitRetrofit.Builder
#addCallAdapterFactory(Factory)

        Retrofit retrofit = Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                .client(okHttpClient)
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(createGsonConverter()))
                .build();
        UserService service = retrofit.create(UserService.class);

メソッドをもう一度見てくださいcreateCallAdapter

  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);
      }
      if (returnType == void.class) {
        throw methodError("Service methods cannot return void.");
      }
      Annotation[] annotations = method.getAnnotations();//获得方法注解
      try {
        //noinspection unchecked
        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);
      }
    }

メソッドの最後で、渡されたRetrofitメソッドはオブジェクトcallAdapterを返しますCallAdapter<T, R>。このcallAdapterメソッドは、メソッドの戻り値の型Type returnType = method.getGenericReturnType();とメソッドの注釈の2 つのパラメータを受け取りますAnnotation[] annotations = method.getAnnotations();注釈をカスタマイズしたい場合は、annotationsこのパラメータを取得する方法を見つける必要があります。

メソッドをもう一度見てくださいcallAdapter

  final List<CallAdapter.Factory> adapterFactories;
   
  public CallAdapter<?, ?> callAdapter(Type returnType, Annotation[] annotations) {
    return nextCallAdapter(null, returnType, annotations);
  }

  public CallAdapter<?, ?> nextCallAdapter(@Nullable CallAdapter.Factory skipPast, Type returnType,
      Annotation[] annotations) {
      
    ...省略部分代码

    int start = adapterFactories.indexOf(skipPast) + 1;//默认会添加一个`CallAdapter<?, ?>`对象
    for (int i = start, count = adapterFactories.size(); i < count; i++) {
      CallAdapter<?, ?> adapter = adapterFactories.get(i).get(returnType, annotations, this);
      if (adapter != null) {
        return adapter;
      }
    }

    ...省略部分代码
  }

メソッドではnextCallAdapter、オブジェクトはトラバーサルadapterFactoriesメソッドCallAdapter.Factoryを通じて取得されますgetCallAdapter<?, ?>

 public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
        Retrofit retrofit);

getメソッドには3 つのパラメータTypeオブジェクトがあります。オブジェクトはインターフェイス メソッドのメソッド アノテーションです。カスタム メソッド アノテーションがある場合、カスタム メソッド アノテーションは の中にありますAnnotation[]したがって、カスタム アノテーションはインターフェイスを実装し、メソッドを通じて追加しますRetrofitAnnotation[]CallAdapter.FactoryRetrofit.Builder
#addCallAdapterFactory(Factory)

Retrofitフレームワークによって提供されるデフォルトのCallAdapter.Factory,它是在在创建Retrofit 对象的时候,通过Retrofit.Builder#buildを見てみましょう方法添加的

      Executor callbackExecutor = this.callbackExecutor;
      if (callbackExecutor == null) {
        callbackExecutor = platform.defaultCallbackExecutor();
      }

      // Make a defensive copy of the adapters and add the default Call adapter.
      List<CallAdapter.Factory> adapterFactories = new ArrayList<>(this.adapterFactories);
      adapterFactories.add(platform.defaultCallAdapterFactory(callbackExecutor));

platform次のdefaultCallAdapterFactory方法を見てください。

  CallAdapter.Factory defaultCallAdapterFactory(@Nullable Executor callbackExecutor) {
    if (callbackExecutor != null) {
      return new ExecutorCallAdapterFactory(callbackExecutor);
    }
    return DefaultCallAdapterFactory.INSTANCE;
  }

設定されている場合はRetrofit.Builder#build.callbackExecutor(Executor executor)それを使用しExecutorCallAdapterFactory、設定されていない場合はそれを使用しますDefaultCallAdapterFactory

クラスを見てみましょうDefaultCallAdapterFactory:

final class DefaultCallAdapterFactory extends CallAdapter.Factory {
  static final CallAdapter.Factory INSTANCE = new DefaultCallAdapterFactory();

  @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 call;
      }
    };
  }
}

上記のコードによれば、コードを作成し、CallAdapter.Factoryそのメソッドget内のカスタム インターフェイス メソッドのアノテーションを解析する方法がわかります。

リクエスト インターフェイスを暗号化する必要があるかどうかを識別するアノテーションをカスタマイズします。

/**
 * 加密注解,在接口方法中添加了这个注解,就代表着这个请求接口传输的数据会进行加密
 */
public @interface Encryption {
    
}

1 つをカスタマイズしますCallAdapter.Factory

public class EncryptionCallAdapterFactory extends CallAdapter.Factory {
    private static final CallAdapter.Factory INSTANCE = new EncryptionCallAdapterFactory();

    public static CallAdapter.Factory create() {
        return INSTANCE;
    }

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

        String baseUrl = retrofit.baseUrl().url().toString();
        String path = null;//请求路径
        boolean hasEncryption = false;//是否有加密注解Encryption
        for (Annotation annotation : annotations) {
            if (annotation instanceof GET) {
                path = ((GET) annotation).value();
            } else if (annotation instanceof POST) {
                path = ((POST) annotation).value();
            } else if (annotation instanceof Encryption) {
                hasEncryption = true;
            }
        }
        if (path != null && hasEncryption) {
            //do something
        }

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

            @Override
            public Call<Object> adapt(Call<Object> call) {
                return call;
            }
        };
    }
}

メソッド内でget、カスタム インターフェイス メソッドのアノテーションを取得し、それを解析します。上記ではリクエストインターフェイスを暗号化していますがget、メソッドではこのリクエストインターフェイスのリクエストエンティティのみを暗号化する必要があり、その後、OKHttpClientインターセプタInterceptorでリクエストエンティティを暗号化する必要があります。

追加EncryptionCallAdapterFactory

        Retrofit retrofit = Retrofit.Builder()
                .baseUrl("https://api.example.com/")
                .client(okHttpClient)
                .addCallAdapterFactory(EncryptionCallAdapterFactory.create())
                .addConverterFactory(GsonConverterFactory.create(createGsonConverter()))
                .build();
        UserService service = retrofit.create(UserService.class);

要約すると、カスタム インターフェイス メソッド アノテーションが主に使用されCallAdapter.Factory、メソッド アノテーションはそのgetメソッド内で取得されて分析されます。ここではインターフェイス メソッドのパラメーターの注釈をカスタマイズできないことに注意してください。

おすすめ

転載: blog.csdn.net/wangjiang_qianmo/article/details/94344924