Retrofit2 Deserialize response body even if response is not 200

孤街浪徒 提交于 2020-01-03 19:16:22

问题


I want to be able to deserialize network response to the same Java object even if response is not succesfull. Currently when I get an error response like 403, the response body is null, and I'm expected to use the response.errorBody() method to read whatever has been sent back, which is ok. However I want to avoid having alot of code in the retrofit callbacks just for deserializing errorBody. Instead I want to have an interceptor that sets the content of errorBody into body.

The reason for this is that I have a response object that has fields for both error and non error responses and depending on the status of the response some fields are expected to be left null e.g

Error Response JSON

{
"locked":true,
"remaining_attempts": 2
}

Success Response JSON

{
"name":"kev"
"token":"abcdefghijklmnopq"
}

I have created a single Java object that captures both scenarios:

class LoginResponse{
    @Expose
    private String name;
    @Expose
    private String token;
    @Expose
    private Boolean locked;
    @Expose
    private Integer remaining_attempts;
}

Is there way to do this in an interceptor?


回答1:


Retrofit is doing the serialization part by delegating it to the Converter, you you can add a specific one to the builder by using builder.addConverterFactory(GsonConverterFactory.create()) and there is already many written Retrofit Converters, you can find most of them here.

so if you want to control this process of deserialization, you can write your custom converter, something like this

public class UnwrapConverterFactory extends Converter.Factory {

    private GsonConverterFactory factory;

    public UnwrapConverterFactory(GsonConverterFactory factory) {
        this.factory = factory;
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(final Type type,
            Annotation[] annotations, Retrofit retrofit) {
        // e.g. WrappedResponse<Person>
        Type wrappedType = new ParameterizedType() {
            @Override
            public Type[] getActualTypeArguments() {
                // -> WrappedResponse<type>
                return new Type[] {type};
            }

            @Override
            public Type getOwnerType() {
                return null;
            }

            @Override
            public Type getRawType() {
                return WrappedResponse.class;
            }
        };
        Converter<ResponseBody, ?> gsonConverter = factory
                .responseBodyConverter(wrappedType, annotations, retrofit);
        return new WrappedResponseBodyConverter(gsonConverter);
    }
}

then you use addConverterFactory() again to tell Retrofit about the new converter. I should mention that you can use multiple converters in Retrofit which is awesome, it simply check converters by order till find the proper one to use.

resources: writing custom Retrofit converter, using multiple converters




回答2:


You can do something like following in response directly...

    LoginResponse errorResponse = gson.fromJson(response.errorBody().string(), LoginResponse.class);

...or using interceptor

addInterceptor(getMyErrorResponseInterceptor())


protected Interceptor getMyErrorResponseInterceptor() {
    return new Interceptor() {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            Response response = chain.proceed(request);
            if (response.code() >= 400) {

                // handle error
            }

            return response;
        }
    };
}


来源:https://stackoverflow.com/questions/44907027/retrofit2-deserialize-response-body-even-if-response-is-not-200

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