要求する
会社の開発では、このような要件が発生
しました。バックグラウンドに送信されるすべてのネットワークリクエストで、bodyパラメータのフィールドの値が空の文字列の場合、このフィールドは削除され、バックグラウンドに送信されません。
たとえば、本文を介して送信するデータが次の長さであるとします。
{
"param1":"1",
"param2":"2",
"param3":"3",
"param4":"",
"param5":null,
}
実際に送信されたパラメーター:
変更前:
{
"param1":"1",
"param2":"2",
"param3":"3",
"param4":""
}
変更後:
{
"param1":"1",
"param2":"2",
"param3":"3"
}
例からわかるように、実装する関数は、Retrofitがリクエストを送信するときに、値が本文の空の文字列であるパラメータを削除することです。
ConverterFactoryをGsonとして指定した後、Retrofitはnull
削除するパラメーターのデフォルト値を削除しますが、パラメーター値は空の文字列であるため、独自に処理する必要があります。パラメーター値を削除すると、空の文字列になります。
デフォルトのGsonConverterFactoryコードとしてConverterFactoryを指定します。
Retrofit retrofit = new Retrofit.Builder() .baseUrl("https://wwww.baidu.com") .addConverterFactory(GsonConverterFactory.create()) .build();
成し遂げる
解決策は実際には難しくありません。Retrofitのコンバーターメカニズムを使用することです。
GsonConverterは私たちのプロジェクトで使用されています:
implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
言い換えると、オブジェクトのシリアル化と逆シリアル化はGsonオブジェクトを使用します。したがって、次のステップは当然、GsonConverterを構成してこの要件を達成する方法を考えることです。
実際、この要件は実装が非常に簡単で、コードは次のとおりです。
TypeAdapter<String> stringTypeAdapter = new TypeAdapter<String>() {
@Override
public String read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull();
return null;
}
/* coerce booleans to strings for backwards compatibility */
if (peek == JsonToken.BOOLEAN) {
return Boolean.toString(in.nextBoolean());
}
return in.nextString();
}
@Override
public void write(JsonWriter out, String value) throws IOException {
// 下面这个if是关键代码,指定序列化时,遇到空串则直接输出null值。
// 由于Gson默认是不序列化null的,所以这里就相当于在序列化时排除了空串的字段
if ("".equals(value)) {
out.nullValue();
return;
}
out.value(value);
}
};
Gson gson = new GsonBuilder().registerTypeAdapter(String.class, stringTypeAdapter).create();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("https://wwww.baidu.com")
.addConverterFactory(GsonConverterFactory.create(gson))
.build();
キーコードは、コードのコメントに記載されているとおりです。
ここでの考え方は、指定されたシリアル化および逆シリアル化ルール変数タイプに対してのみを指定するGson
ことTypeAdapter
ですString
。
このString
タイプTypeAdapter
の記述に関しては、実際Gson
にはオブジェクトのソースコードを参照しています。
考え
この要件に最初に遭遇したとき、私はおそらく方向性を知っていましたが、具体的な詳細を達成する方法を知りませんでした。シリアル化と逆シリアル化を実現するためにRetrofit
、自分で定義できることだけを知っていますConverter
。しかし、String
逆シリアル化しない型の空の文字列を実装する方法がわかりません。
私の考えは
次のとおりです。まず、GsonConverterFactory.create()メソッドにパラメーターを持つメソッドがありますGsonConverterFactory.create(Gson gson)
。次に、要件を実現Factory
するgson
オブジェクトを構成することで、この要件を達成できます。
次に、Gson
このnull
タイプのオブジェクトはデフォルトではシリアル化されません。これはどのように達成されますか?これを理解すれば、同じ方法でGson
空の文字列を逆シリアル化できると思います。
それから、上記の考えに基づいて、私Gson
はソースコードを見始めました。私は次の段落を見ました:
public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
1つはここTypeAdapterFactory
で定義されており、これは明らかにString
型を処理するために使用されます。後でnewFactory
メソッドに渡されるSTRING
オブジェクトの定義は次のとおりです。
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
@Override
public String read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull();
return null;
}
/* coerce booleans to strings for backwards compatibility */
if (peek == JsonToken.BOOLEAN) {
return Boolean.toString(in.nextBoolean());
}
return in.nextString();
}
@Override
public void write(JsonWriter out, String value) throws IOException {
out.value(value);
}
};
ここを参照してください。最後に、ここで行う必要があるのは、write
contentメソッドを再定義することです。
Gsonはデフォルトnull
ではシリアル化されていないため、文字列が空のときにnull
値を出力するように指定できます。このようにして、デフォルトで、空の文字列を出力しないという目標を達成できます。
スペースに限りがありますので、実際に読んで確認した内容は上記の内容をはるかに上回っていますが、上記の内容がポイントであり、他の内容も自分の工夫で扱えると思います。Gsonのソースコード自体は難しくないからです。