Search code examples
androidretrofitillegalstateexception

Retrofit 2 - Converted object is null when using Interceptor


I am using an Interceptor to able to see raw response from the server:

public WebServiceClient() {
    OkHttpClient client = new OkHttpClient();
    client.interceptors().add(new Interceptor() {
        @Override
        public Response intercept(Interceptor.Chain chain) throws IOException {
            Response response = chain.proceed(chain.request());
            Log.d(TAG, UtilityMethods.convertResponseToString(response));
            return response;
        }
    });
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://anlatbanaapi.paradoks.biz")
            .addConverterFactory(GsonConverterFactory.create())
            .client(client)
            .build();
    tellMeServices = retrofit.create(TellMeServices.class);
}

public Call<GetCategoryResponse> getCategories(){
    Map<String, Object> requestMap = new HashMap<>();
    Long unixTime = System.currentTimeMillis() / LONG_1000;
    requestMap.put(KEY_TIME, unixTime);
    JWTSigner signer = new JWTSigner(SECRET);
    String token = signer.sign(requestMap);
    return tellMeServices.getCategories(token);
}

But when I use Interceptor I get null as converted object:

WebServiceClient webServiceClient = new WebServiceClient();
Call<GetCategoryResponse> call = webServiceClient.getCategories();
call.enqueue(new Callback<GetCategoryResponse>() {
    @Override
    public void onResponse(Response<GetCategoryResponse> response, Retrofit retrofit) {
        GetCategoryResponse getCategoryResponse = response.body();

        // Always null if I use Interceptor
        if (getCategoryResponse == null) {
            Log.e(TAG, "Converted response is null!");
            return;
        }

        if (getCategoryResponse.succes == 1) {

            for (Category category : getCategoryResponse.categoryList) {
                Log.d(TAG, category.toString());
            }
        }
        else {
            Log.e(TAG, getActivity().getString(R.string.something_really_bad_happened));
            Toast.makeText(getContext(), R.string.failed_to_get_categories, Toast.LENGTH_LONG).show();
        }
    }

    @Override
    public void onFailure(Throwable t) {
        Log.e(TAG, t.getLocalizedMessage());
    }
});

If I don't use Interceptor I am not able to get raw response. When I try to get raw response I am gettin following error:

FATAL EXCEPTION: main
Process: com.yceo.anlatbana, PID: 25656
java.lang.IllegalStateException: Cannot read raw response body of a converted body.
    at retrofit.OkHttpCall$NoContentResponseBody.source(OkHttpCall.java:184)
    at com.squareup.okhttp.ResponseBody.byteStream(ResponseBody.java:43)
    at com.yceo.anlatbana.util.UtilityMethods.convertResponseToString(UtilityMethods.java:126)
    at com.yceo.anlatbana.CategoryFragment$2.onResponse(CategoryFragment.java:166)
    at retrofit.ExecutorCallAdapterFactory$ExecutorCallback$1.run(ExecutorCallAdapterFactory.java:86)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:135)
    at android.app.ActivityThread.main(ActivityThread.java:5310)
    at java.lang.reflect.Method.invoke(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:372)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:904)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:699)

Solution

  • You can only read the Response once since it is a stream. You are reading it in your UtilityMethods.convertResponseToString method, so you need to create a new Response with the same content.

    client.interceptors().add(new Interceptor() {
            @Override
            public Response intercept(Interceptor.Chain chain) throws IOException {
                Response response = chain.proceed(chain.request());
                final String content = UtilityMethods.convertResponseToString(response));
                Log.d(TAG, content);
                return response.newBuilder()
                    .body(ResponseBody.create(response.body().contentType(), content))
                    .build();
            }
        });