Retrofit2.0ノート——addConverterFactoryはxmlとjson形式の応答データを同時にサポートする

6535 ワード

Retrofit 2の特徴的な機能は、addConverterFactory()の方法でデータ変換器を設定することで、httpリクエストの応答データをJavaBeanに変換することができます.バックグラウンドで一般的な2つの戻りデータフォーマット:jsonとxmlのように、それぞれGsonConverterFactorySimpleXmlConverterFactoryで変換できます.対応するgradle依存度は、次のとおりです.
implementation 'com.squareup.retrofit2:converter-gson:2.x.x'
implementation 'com.squareup.retrofit2:converter-simplexml:2.x.x'

注意:SimpleXmlConverterFactoryは現在Deprecatedとして宣言されており、推奨される代替案はJAXB converter(JaxbConverterFactory)であり、対応するgradle依存は以下の通りである.
implementation 'com.squareup.retrofit2:converter-jaxb:2.x.x'

しかし、実測の結果、このコンバータはRetrofitに設定された後、正常に動作しない.
デフォルトでは、Gson(JSON)とSimpleXML(XML)変換器の動作のため、1つのRetrofitインスタンスでは両方の変換器を同時にサポートできません.このように書くと、
Retrofit mRetrofit = new Retrofit.Builder()
                .baseUrl(URL)
                .addConverterFactory(SimpleXmlConverterFactory.create())
                .addConverterFactory(GsonConverterFactory.create())
                .build();

では,xmlフォーマットを変換した戻りデータは正常であり,jsonフォーマットを変換した戻りデータはクラッシュする.このように書くと、
Retrofit mRetrofit = new Retrofit.Builder()
                .baseUrl(URL)
                .addConverterFactory(GsonConverterFactory.create())
                .addConverterFactory(SimpleXmlConverterFactory.create()
                .build();

では、jsonフォーマットを変換する戻りデータは正常であり、xmlフォーマットを変換する戻りデータはクラッシュする.つまり、先に追加したものだけが正常に使えます.
では、jsonとxmlフォーマットを同時に正常に変換できる案はありますか?あるに違いない!
解決策
Retrofitが呼び出すインタフェースメソッドに注釈を追加し、リクエストの応答データフォーマットを説明します.次にConverterFactoryをカスタマイズし、注記のプロパティ値に基づいてjsonコンバータを使用するかxmlコンバータを使用するかを決定します.
インプリメンテーションコードResponseFormatなどのカスタム注釈:
/**
 *          ,      :{@link #JSON} {@link #XML}
 */
@Target(METHOD)
@Retention(RUNTIME)
public @interface ResponseFormat {

    String JSON = "json";

    String XML = "xml";

    String value() default "";
}

カスタムConverterFactory(JsonOrXmlConverterFactoryなど)
public class JsonOrXmlConverterFactory extends Converter.Factory {

    private final Converter.Factory xmlFactory = SimpleXmlConverterFactory.create();
    private final Converter.Factory jsonFactory = GsonConverterFactory.create();

    public static JsonOrXmlConverterFactory create() {
        return new JsonOrXmlConverterFactory();
    }

    @Nullable
    @Override
    public Converter responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        for (Annotation annotation : annotations) {
            if (!(annotation instanceof ResponseFormat)) {
                continue;
            }
            String value = ((ResponseFormat) annotation).value();
            if (ResponseFormat.JSON.equals(value)) {
                return jsonFactory.responseBodyConverter(type, annotations, retrofit);
            } else if (ResponseFormat.XML.equals(value)) {
                return xmlFactory.responseBodyConverter(type, annotations, retrofit);
            }
        }

        return null;
    }
}

テストコード
interface TestApi {
        @GET("testapi/getjson.php/")
        @ResponseFormat("json")
        Observable getJson();

        @GET("testapi/getxml.php/")
        @ResponseFormat("xml")
        Observable getXml();
    }

//……
Retrofit mRetrofit = new Retrofit.Builder()
               .baseUrl(URL)
               .addConverterFactory(JsonOrXmlConverterFactory.create()
               .build();
//……

public void getCode(Consumer consumer) {
    TestApi testApi = mRetrofit.create(TestApi.class);
    testApi.getJson()
            .subscribe(consumer);
}

public void getXml(Consumer consumer) {
    TestApi testApi = mRetrofit.create(TestApi.class);
    testApi.getXml()
            .subscribe(consumer);
}

まとめ
この問題には解決策があるが、需要シーンは少ないはずだ.一般的なバックグラウンドサービスは、同じbaseUrlベースのapiインタフェースであり、一般的には統合応答データフォーマットである.appで異なるバックグラウンドサービスurlからデータを要求する必要がある場合にのみ、Retrofit自体がマルチbaseUrlをサポートする複数のフォーマットの戻りデータが発生する可能性があります.