記事ディレクトリ
インターフェースメソッドとメソッドパラメータのアノテーション
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
内の静的内部クラスBuilder
のbuild
メソッド内で行われ、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) メソッド。上の例のように:invoke
invoke
@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
です。Object
2 つ目は、実行されたメソッドがターゲット インターフェイス (UserService) で宣言されたデフォルト メソッドであるかどうかを判断することです (Java 8.0 以降、デフォルト メソッドはインターフェイスで宣言できます)。
if (platform.isDefaultMethod(method)) {
return platform.invokeDefaultMethod(method, service, proxy, args);
}
Platform
主な違いは Android か Java です。最後にServiceMethod
、OkHttpCall
オブジェクトを作成し、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
上記のアノテーション解析処理から、クラス内の静的内部クラスBuilder
のbuild
メソッド内でアノテーション解析が行われていることが分かります。build
メソッドのコードの最初の行をもう一度見てください。
callAdapter = createCallAdapter(); //创建一个 CallAdapter 对象
createCallAdapter()
メソッドはCallAdapter<T, R>
オブジェクト。リクエスト結果のレスポンスタイプをカスタムタイプに変換するCallAdapter<R, T>
機能を持つインターフェースです。オブジェクトはクラスを通じて作成されます。これは、オブジェクトの作成時にメソッドによって追加されます。R
T
CallAdapter
CallAdapter.Factory
Retrofit
Retrofit.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
を通じて取得されます。get
CallAdapter<?, ?>
public abstract @Nullable CallAdapter<?, ?> get(Type returnType, Annotation[] annotations,
Retrofit retrofit);
get
メソッドには3 つのパラメータType
とオブジェクトがあります。オブジェクトはインターフェイス メソッドのメソッド アノテーションです。カスタム メソッド アノテーションがある場合、カスタム メソッド アノテーションは の中にありますAnnotation[]
。したがって、カスタム アノテーションはインターフェイスを実装し、メソッドを通じて追加します。Retrofit
Annotation[]
CallAdapter.Factory
Retrofit.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
メソッド内で取得されて分析されます。ここではインターフェイス メソッドのパラメーターの注釈をカスタマイズできないことに注意してください。