Retrofit2 error java.io.EOFException: End of input at line 1 column 1
AndroidWeb ServicesRetrofit2Android Problem Overview
I called PATCH web service using Retrofit2 but onResponse is not called and the onFailure is called Despite of the operation of the service is succeeded on the server side perfectly
And whenever,I tried to use fiddler to check the service its working , i found the problem is that serializing the coming response of the service and when using fiddler i found that no content of the JSON response so the Retrofit service assumed that its failed because there is no content and it cannot serialize the EMPTY content and give me this error
java.io.EOFException: End of input at line 1 column 1
Fiddler raw Response
HTTP/1.1 200 OK
Server: nginx/1.9.4
Date: Wed, 02 Mar 2016 09:55:55 GMT
Content-Type: application/json
Content-Length: 0
Connection: close
Status: 200 OK
X-Content-Type-Options: nosniff
Fiddler Json Response is empty
webservice in java
Call<Object> call = TimeCapp.services.accept_invited_alerts(HomeActivity.api_token, alert_id);
call.enqueue(new Callback<Object>()
{
@Override
public void onResponse (Call<Object> call, Response<Object> response)
{
if (response.isSuccess()) {
String x = response.body();
}
}
@Override
public void onFailure (Call<Object>call, Throwable t)
{
String x = t.getMessage();//java.io.EOFException: End of input at line 1 column 1
}
}
I tried to replace object with String,JsonObject,emptyCalssBody .... but its failed
the interface of the webservice
@PATCH("alerts/{alert_id}/accept")
Call<Object> accept_invited_alerts(@Header("X-Api-Token") String
api_token, @Path("alert_id") int alert_id);
Android Solutions
Solution 1 - Android
just return void instead, if the body is empty
@PATCH("alerts/{alert_id}/accept") Call<Void> accept_invited_alerts(@Header("X-Api-Token") String api_token, @Path("alert_id") int alert_id);
for retrofit with Rx java you can use something like this
@PATCH("alerts/{alert_id}/accept") Observable<Response<Void>> accept_invited_alerts(@Header("X-Api-Token") String api_token, @Path("alert_id") int alert_id);
EDIT: For kotlin
@PATCH("alerts/{alert_id}/accept")
fun accept_invited_alerts(@Header("X-Api-Token") api_token: String, @Path("alert_id") alert_id: Int): Call<Unit>
and
@PATCH("alerts/{alert_id}/accept")
fun accept_invited_alerts(@Header("X-Api-Token") api_token: String, @Path("alert_id") alert_id: Int): Observable<Response<Unit>>
Solution 2 - Android
You can create NullOnEmptyConverterFactory.class :
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;
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);
}
};
}
}
and add to code create. For ex:
UploadImageNghiemThuApi uploadService = new Retrofit.Builder()
.baseUrl(Config.URL+"/")
.client(okHttpClient)
// -----add here-------
.addConverterFactory(new NullOnEmptyConverterFactory())
//---------------------
.addConverterFactory(GsonConverterFactory.create())
.build()
.create(UploadImageNghiemThuApi.class);
I hope it can help your problem. Thanks!
EDIT !!!
For a kotlin usecase you can check this
class NullOnEmptyConverterFactory : Converter.Factory() {
override fun responseBodyConverter(
type: Type,
annotations: Array<Annotation>,
retrofit: Retrofit
): Converter<ResponseBody, *> {
val delegate: Converter<ResponseBody, *> =
retrofit.nextResponseBodyConverter<Any>(this, type, annotations)
return Converter { body -> if (body.contentLength() == 0L) null else delegate.convert(body) }
}
}
Solution 3 - Android
Thank you very much.
Api
@FormUrlEncoded
@POST("/rebu/insertusuario.php")
Call<Void> insertLogin(
@Field("email") String email,
@Field("senha") String senha,
@Field("codCondutor") Long codCondutor
);
Class:
Call call = service.insertLogin(login.getEmail(), login.getSenha(), login.getCodCondutor());
Solution 4 - Android
For me in laravel I was not sending any response after function completed just adding the following lines on server side helped. This can be adapted to the language you are using. Just send some response from server side.
use Response;
return Response::json(array(
'result' => 'success',
));