I use:

implementation group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.4.0' implementation group: 'com.squareup.retrofit2', name: 'adapter-rxjava2', version: '2.4.0' implementation group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.4.0' 

There is an API request that returns Observable<Response<List<String>>> .

If the server returns a valid json, then I get the desired object. If an error occurred during the request, the server returns nothing and I get the error Caused by: java.io.EOFException: End of input at line 1 column 1 path $ .

Is it possible to somehow get null instead of List<String> ?

Those. with a well-formed query, I can return a List<String> , but if the user does not specify any data, then I cannot query the database and return the result. Those. this is not a server error (5xx), it is a client error (4xx).

I want to get the server response code, but due to the fact that "" is not parsed in the List<String> I get java.io.EOFException and cannot find out what kind of client error (4xx) occurred. Because onError is onError when subscribe , and Response<List<String> falls into onNext .

1) I can give an empty array, but what to do with single objects? Yes, and this approach seems to me wrong. If the data could not be generated for a response, then nothing needs to be returned, only the response code in the header.

2) I thought to always take Observable<Response<String>> and to parse already upon receipt (empty string and any other pass). I will get the server response code and, if successful (201 notes), I will parse the String. But again, it seems a very unfortunate decision.

  • mb catch through try / catch and pull out an error there - Romanych
  • @ Romanych Observable <Response <List <String >>> when subscribe, two callbacks twitch, one at successful execution, the other at error. I do not want to refuse RxJava, because extremely comfortable working with her. There must be a way to solve the problem, I'm sure :) but I don’t know how yet. Those. try / catch are hidden from me, I just get a throwable, and all the same with this approach, I get only a throwable, and I need a Response <T>. - Eugene

1 answer 1

I decided this way (I found the answer on https://github.com/square/retrofit/issues/1554 , but I had to change the solution a bit, because something has changed in retrofit2 since 2016):

 private class NullOnEmptyConverterFactory extends Converter.Factory { @Nullable @Override public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) { final Converter<ResponseBody, ?> delegate = retrofit.nextResponseBodyConverter(this, type, annotations); return (Converter<ResponseBody, Object>) value -> { try { return delegate.convert(value); } catch (Exception e) { return null; } }; } } 

after

 Retrofit retrofit = new Retrofit.Builder() .baseUrl("http://your_url") .addConverterFactory(new NullOnEmptyConverterFactory()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .addConverterFactory(ScalarsConverterFactory.create()) .addConverterFactory(GsonConverterFactory.create()) .build(); 

It works like this:

 AppService.INSTANCE.forDebug().subscribe( res -> { // Если Gson может распарсить ответ в List<String> - мы его получаем в res.body() // Если сервер вернет "" или "любые невалидные данные" - мы получаем null if (res.body() == null) { return; } // Обработка res.code() // Логика приложения }, err -> { // Обработка ошибок, т.е. есил сюда попала ошибка, то это вина android разработчика // Все ошибки сервера 4хх или 5хх попадают в res } ); 

As a result, convenient interfaces to call API

 @GET("for_debug.php") Observable<Response<List<String>>> forDebug();