Skip to content

Handle Empty Body #1554

Closed
Closed
@roybrener

Description

@roybrener

After updating to retrofit beta-3 I'm getting the Exception (Because of an empty body)

java.io.EOFException: End of input at line 1 column 1
                                                                           at com.google.gson.stream.JsonReader.nextNonWhitespace(JsonReader.java:1414)
                                                                           at com.google.gson.stream.JsonReader.doPeek(JsonReader.java:553)
                                                                           at com.google.gson.stream.JsonReader.peek(JsonReader.java:429)
                                                                           at com.google.gson.internal.bind.ReflectiveTypeAdapterFactory$Adapter.read(ReflectiveTypeAdapterFactory.java:202)
                                                                           at com.google.gson.TypeAdapter.fromJson(TypeAdapter.java:260)
                                                                           at retrofit2.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:33)
                                                                           at retrofit2.GsonResponseBodyConverter.convert(GsonResponseBodyConverter.java:23)
                                                                           at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:154)
                                                                           at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:92)
                                                                           at okhttp3.RealCall$AsyncCall.execute(RealCall.java:133)

I know that It's possible to solve this issue Using Call<Void> but is there any other way to enforce OkHttp or Gson To accept Empty body?

Response Log:

 D/OkHttp: Date: Mon, 01 Feb 2016 08:32:10 GMT
D/OkHttp: Server: Apache/2.4.7 (Ubuntu)
D/OkHttp: X-Powered-By: PHP/5.5.9-1ubuntu4.13
D/OkHttp: Expires: Thu, 19 Nov 1981 08:52:00 GMT
D/OkHttp: Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
D/OkHttp: Pragma: no-cache
D/OkHttp: Access-Control-Allow-Origin: https://example.com
D/OkHttp: Access-Control-Allow-Methods: GET,POST,OPTIONS
D/OkHttp: Access-Control-Allow-Headers: Accept,Cache-Control,Pragma,Origin,Authorization,Content-Type,X-Requested-With,Cookie,*
D/OkHttp: Access-Control-Allow-Credentials: true
D/OkHttp: Content-Length: 0
D/OkHttp: Keep-Alive: timeout=5, max=99
D/OkHttp: Connection: Keep-Alive
D/OkHttp: Content-Type: application/json
D/OkHttp: OkHttp-Sent-Millis: 1454315528548
D/OkHttp: OkHttp-Received-Millis: 1454315528725
D/OkHttp: <-- END HTTP (0-byte body)

Activity

FabianTerhorst

FabianTerhorst commented on Feb 1, 2016

@FabianTerhorst

Are you getting the same error when you don´t set a converter factory?

roybrener

roybrener commented on Feb 1, 2016

@roybrener
Author

I didn't test without the converter. I guess it will not fail because GsonResponseBodyConverter.convert will not run. Is there any reason why i should check without the converter?

JakeWharton

JakeWharton commented on Feb 1, 2016

@JakeWharton
Collaborator

What behavior do you expect when the body is empty then?

You are telling Retrofit to deserialize the response as a certain object and Retrofit tells Gson to parse the stream into that type and the type is empty. This behavior already seems very reasonable to me.

roybrener

roybrener commented on Feb 2, 2016

@roybrener
Author

Just return an "empty" pojo response (Like it was until now)... all fields null? It's a real problem...for example I didn't write the server side, just the Android App...The server side returns 200 with empty body...but there are times that the same call will return a 200 with a body message. I have nothing to do in situations like that

JakeWharton

JakeWharton commented on Feb 2, 2016

@JakeWharton
Collaborator

An empty pojo is {} in JSON.

You can write a delegating converter that does this, the behavior will not be added to Retrofit by default.

class NullOnEmptyConverterFactory implements Converter.Factory {
  @Override public Converter<ResponseBody, ?> responseBody(Type type, Annotation[] annotations, Retrofit retrofit) {
    final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
    return new Converter<>() {
      @Override public void convert(ResponseBody body) {
        if (body.contentLength() == 0) return null;
        return delegate.convert(body);
      }
    };
  }
}
Retrofit retrofit = new Retrofit.Builder()
    .endpoint(..)
    .addConverterFactory(new NullOnEmptyConverterFactory())
    .addConverterFactory(GsonConverterFactory.create())
    .build();
TheHal85

TheHal85 commented on Apr 21, 2016

@TheHal85

I had to implement this for a requirement from my services team. Here is the updated code I used for release version of Retrofit 2.0 that seems to be working in case anyone else comes across the issue.

public class NullOnEmptyConverterFactory extends Converter.Factory {

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
        final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations);
            return new Converter<ResponseBody, Object>() {
                @Override
                public Object convert(ResponseBody body) throws IOException {
                    if (body.contentLength() == 0) return null;
                    return delegate.convert(body);                }
            };
    }
}
nAkhmedov

nAkhmedov commented on May 12, 2016

@nAkhmedov

body.contentLength() always returns -1 on me. What to do?

JakeWharton

JakeWharton commented on May 12, 2016

@JakeWharton
Collaborator

Just read it. That means unknown content length.

On Wed, May 11, 2016, 11:51 PM nAkhmedov notifications@github.com wrote:

body.contentLength() always returns -1 on me. What to do?


You are receiving this because you modified the open/close state.

Reply to this email directly or view it on GitHub
#1554 (comment)

nAkhmedov

nAkhmedov commented on May 12, 2016

@nAkhmedov

05-12 11:57:35.040 12039-13092/com.sms.sendsms D/OkHttp: <-- 200 OK http://www.yesplease.co.il/app/login.asp?username=zolim2&password=123456g (554ms)
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Cache-Control: must-revalidate,no-cache,private
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Content-Type: text/html; Charset=utf-8
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Expires: Wed, 11 May 2016 06:58:56 GMT
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Vary: Accept-Encoding
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Server: Microsoft-IIS/7.5
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: X-Powered-By: Yes Please
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Server: Server
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Date: Thu, 12 May 2016 06:58:56 GMT
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Connection: Keep-Alive
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Set-Cookie: source=; path=/
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: Set-Cookie: ASPSESSIONIDCSASTAQA=NCLNDGIBMFFIEGMOBHIABCEC; path=/
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: OkHttp-Sent-Millis: 1463036254545
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: OkHttp-Received-Millis: 1463036255040
05-12 11:57:35.041 12039-13092/com.sms.sendsms D/OkHttp: <-- END HTTP (0-byte body)
05-12 11:57:35.081 12039-12039/com.sms.sendsms W/System.err: java.io.EOFException: End of input at line 1 column 1

nAkhmedov

nAkhmedov commented on May 12, 2016

@nAkhmedov

HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();//If need to logging, just uncomment
interceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
OkHttpClient client = new OkHttpClient.Builder()
.addInterceptor(interceptor)
.build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(ContextConstants.APP_URL)
.addConverterFactory(new NullOnEmptyConverterFactory())
.addConverterFactory(GsonConverterFactory.create())
.client(client)
.build();

AllenVork

AllenVork commented on Jul 19, 2016

@AllenVork

I add the NullOnEmptyConverterFactory to the retrofit, and still gets the error.Then I find the order is important.

Retrofit retrofit = new Retrofit.Builder()
    .endpoint(..)
    .addConverterFactory(new NullOnEmptyConverterFactory()) //this should come first
    .addConverterFactory(GsonConverterFactory.create())
    .build();
omarmiatello

omarmiatello commented on Jul 29, 2016

@omarmiatello

help for Kotlin devs

val nullOnEmptyConverterFactory = object : Converter.Factory() {
    fun converterFactory() = this
    override fun responseBodyConverter(type: Type, annotations: Array<out Annotation>, retrofit: Retrofit) = object : Converter<ResponseBody, Any?> {
        val nextResponseBodyConverter = retrofit.nextResponseBodyConverter<Any?>(converterFactory(), type, annotations)
        override fun convert(value: ResponseBody) = if (value.contentLength() != 0L) nextResponseBodyConverter.convert(value) else null
    }
}

45 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @JakeWharton@eriknyk@kcorey@Shubhampatni86@crisu83

        Issue actions

          Handle Empty Body · Issue #1554 · square/retrofit