Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug : Problem with response body, not parsing body if response is 202 #3276

Open
mangeshsambare opened this issue Jan 8, 2020 · 6 comments

Comments

@mangeshsambare
Copy link

I know that Retrofit does not allow the Call without any return types, developer should have to add some object in return type like

@GET
 Call<Response<JsonObject>> checkStatus(@Url String url);

Above is client application request checking status of data. In this request, client app gets two types of different responses 200 success with body & 202 accepted without body. Client app have to call this request with an interval of 5 or n seconds whenever in response client app gets 202 accepted response. If other than 202 it gets different status code then client app stops this calling this request.

So in this case, client app accept return type of Response<JsonObject> In 202 accepted response there is no body. So it is gives error :

Retrofit2 error java.io.EOFException: End of input at line 1 column 1

I changed this Response<JsonObject> to Response<Object> & Response<String>, but still gives same above error.

So I solved this issue by changing return type of request from Response<JsonObject> to Response<Void> as it is suggested here

@GET
 Call<Response<Void>> checkStatus(@Url String url);

Now above request is working fine for 202 accepted response. But not working when client app gets 200 success response & in that response server sends body in it. In Response object app can not gets body because of return type Void.

In above request of return type I use Response object like Call<Response>. I use this object because client app needs to check HTTP status code like 200, 202 etc. I changed from Call<Response> to Call<ResponseBody> but it does not return status code. Only Call<Response> object returns HTTP status code.

In same request, how can I handle null/empty body if I get 202 accepted status code & body data if I get 200 success status code?

I know that, Retrofit does not allow Call without type like Call<Response<Void>> or Call<Response<JsonObject>> and is not able to map empty body, but what if one of developer have above use case? How can it will be solve? I don't know about any standardization of accepting body only if 200 & not in 202, is there any standard way to do this?

@ctlove0523
Copy link
Contributor

I through modify converter solved this problem. For example,i modify the JacksonResponseBodyConverter so when server not return response body the converter return a default value:

  @Override
  public T convert(ResponseBody value) throws IOException {
    try {
      if (value.contentLength() == 0) {
        return (T) new Object();
      }
      return adapter.readValue(value.charStream());
    } finally {
      value.close();
    }
  }

I test it and works well,but I don't know other people need it or not?

@zjc17
Copy link

zjc17 commented May 30, 2020

I've write test scenario in CallTest.java, but it passed. This commit link is here.

I would like you help me to reconstruct your case, so that one can help you to solve this issue.

@mangeshsambare
Copy link
Author

@Jiachen-Zhang Thanks for your help. I gone through your code. In your test case you set body empty string.
server.enqueue(new MockResponse().setResponseCode(202).setBody(""));

Instead of empty body just try null means Void. You will get error. From server my application get null body & response is 202 and it is successfully works with other client application like iOS, Java SpringBoot.

Please do send null in body

@BMarton
Copy link

BMarton commented Nov 4, 2020

hey @mangeshsambare did you figure this out? just bumped into something similar and i've tried a few different approaches:

  • using Call<Void>,
  • using Call<ResponseBody>,
  • using a custom Converter.Factory, like the NullOnEmptyConverterFactory you'll find here.

unfortunately no luck yet, i'd appreciate some help.

@celiluysal
Copy link

celiluysal commented Jul 27, 2024

@BMarton You can return a default value if contentLength Is zero using retrofit2.Converter.Factory, it works for me
link

import okhttp3.ResponseBody
import retrofit2.Converter
import retrofit2.Retrofit
import java.lang.reflect.Type

class EmptyResponseBodyConverterFactory() : Converter.Factory() {

    override fun responseBodyConverter(
        type: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, *> {
        val delegate = retrofit.nextResponseBodyConverter<Any>(this, type, annotations)
        return Converter { body ->
            if (body.contentLength() == 0L) {
                // Return a default instance of the expected type or null if appropriate
                return@Converter null
            } else {
                return@Converter delegate.convert(body)
            }
        }
    }
}
Retrofit.Builder()
            .client(client)
            .addConverterFactory(EmptyResponseBodyConverterFactory())
            .addConverterFactory(MoshiConverterFactory.create(moshi))

@ctlove0523
Copy link
Contributor

ctlove0523 commented Jul 27, 2024 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants