Retrofit multiple response types

為{幸葍}努か 提交于 2021-02-08 09:13:48

问题


How can I use Retrofit2 to parse these two kinds of API responses?

Ok response (HTTP 200):

{
    "data": {
        "foo": "bar"
    }
}

Error response (HTTP 200):

{
    "error": {
        "foo": "bar"
    }
}

I've read tons of SO questions and tutorials, but I don't know how to do that, I've tried:

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.registerTypeAdapterFactory(new ItemTypeAdapterFactory());
Gson gson = gsonBuilder.create();

final Retrofit retrofit = new Retrofit.Builder()
        .client(getOkHttpClient())
        .baseUrl(Constants.API_BASE_URL)
        .addConverterFactory(GsonConverterFactory.create(gson))
        .build();

And this is my ItemTypeAdapterFactory:

class ItemTypeAdapterFactory implements TypeAdapterFactory {

    public <T> TypeAdapter<T> create(final Gson gson, final TypeToken<T> type) {

        final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
        final TypeAdapter<JsonElement> elementAdapter = gson.getAdapter(JsonElement.class);

        return new TypeAdapter<T>() {

            public void write(JsonWriter out, T value) throws IOException {
                delegate.write(out, value);
            }

            public T read(JsonReader in) throws IOException {

                JsonElement jsonElement = elementAdapter.read(in);

                if (jsonElement.isJsonObject()) {
                    JsonObject jsonObject = jsonElement.getAsJsonObject();

                    // Data key
                    if (jsonObject.has(Constants.JSON_KEY_DATA)) {

                        JsonElement jsonData = jsonObject.get(Constants.JSON_KEY_DATA);

                        // Primitive
                        if (jsonData.isJsonPrimitive()) {
                            jsonElement = jsonData.getAsJsonPrimitive();
                        }
                        // JSON object
                        else if (jsonData.isJsonObject()) {
                            jsonElement = jsonData;
                        }
                        // JSON object array
                        else if (jsonData.isJsonArray()) {
                            jsonElement = jsonData.getAsJsonArray();
                        }
                    }
                }

                return delegate.fromJsonTree(jsonElement);
            }
        }.nullSafe();
    }
}

But now I don't know the type to be declared on retrofit2 interface, inside Call:

@GET("login")
Call<?> login(@Query(Constants.API_PARAM_TOKEN) String token);

Could you please point me in the right direction?


回答1:


In a similar case, I once used JsonObject as type, so your function will look like this:

@GET("login")
Call<?> login(@Query(Constants.API_PARAM_TOKEN) String token);

Next, when you make a retrofit call, you keep the response as a string. So, in your java code, do something like this:

Call<JsonObject> call = RetrofitClient.getAPIService().login('YOUR_INPUT');
Data data = null;
Error error = null;
call.enqueue(new Callback<JsonObject>() {
            @Override
            public void onResponse(Call<JsonObject> call, Response<JsonObject> response) {
if(response.isSuccessfull()){
  String jsonString = response.body().toString();
  if(jsonString.contains("data:")){
       data = new Gson().fromJson(jsonString,Data.class);
  }else{
      error = new Gson().fromJson(jsonString,Error.class);
  }
}
        }

Here, I have used Data and Error these 2 classes. They are the POJOs. So Data can look something like this:

Data.java:

public class Data implements Serializable{
 @SerializedName("foo")
    @Expose
    private Foo foo; // Foo is your desired data type 

}

Same goes for Error. So depending on your rest of the code, make necessary changes. Good luck.



来源:https://stackoverflow.com/questions/59945168/retrofit-multiple-response-types

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!