Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Retrofit 2.6.0 exception: java.lang.IllegalArgumentException: Unable to create call adapter for kotlinx.coroutines.Deferred

I have a project with Kotlin coroutines and Retrofit.

I had these dependencies:

implementation 'com.squareup.retrofit2:retrofit:2.5.0' implementation 'com.squareup.retrofit2:converter-gson:2.5.0' implementation 'com.jakewharton.retrofit:retrofit2-kotlin-coroutines-adapter:0.9.2' 

Today I have updated Retrofit to 2.6.0 in the project. In https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter it is written that it is deprecated now. In https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05 it is written that Retrofit currently supports suspend.

So, I removed retrofit2-kotlin-coroutines-adapter:0.9.2 and in Retrofit client changed these lines:

        retrofit = Retrofit.Builder()             .baseUrl(SERVER_URL)             .client(okHttpClient)             .addConverterFactory(MyGsonFactory.create(gson))             //.addCallAdapterFactory(CoroutineCallAdapterFactory()) - removed it.             .build() 

When run, the first request catches an exception:

java.lang.IllegalArgumentException: Unable to create call adapter for kotlinx.coroutines.Deferred<com.package.model.response.UserInfoResponse>     for method Api.getUserInfo 

As I understood, instead of CoroutineCallAdapterFactory() I could use CallAdapter.Factory(), but it is abstract.

If in Api class I change a request adding suspend in the beginning:

@FormUrlEncoded @POST("user/info/") suspend fun getUserInfo(@Field("token") token: String): Deferred<UserInfoResponse>  override suspend fun getUserInfo(token: String): Deferred<UserInfoResponse> =     service.getUserInfo(token) 

I get this exception:

java.lang.RuntimeException: Unable to invoke no-args constructor for kotlinx.coroutines.Deferred<com.package.model.response.UserInfoResponse>. Registering an InstanceCreator with Gson for this type may fix this problem. 
like image 358
CoolMind Avatar asked Jun 06 '19 08:06

CoolMind


1 Answers

Reading https://github.com/square/retrofit/blob/master/CHANGELOG.md#version-260-2019-06-05 I saw:

New: Support suspend modifier on functions for Kotlin! This allows you to express the asynchrony of HTTP requests in an idiomatic fashion for the language.

@GET("users/{id}") suspend fun user(@Path("id") long id): User

Behind the scenes this behaves as if defined as fun user(...): Call and then invoked with Call.enqueue. You can also return Response for access to the response metadata.

Currently this integration only supports non-null response body types. Follow issue 3075 for nullable type support.

I changed requests so: added suspend and removed Deferred:

@FormUrlEncoded @POST("user/info/") suspend fun getUserInfo(@Field("token") token: String): UserInfoResponse   override suspend fun getUserInfo(token: String): UserInfoResponse =     service.getUserInfo(token) 

Then in interactor (or simply when called the method getUserInfo(token)) removed await():

override suspend fun getUserInfo(token: String): UserInfoResponse =     // api.getUserInfo(token).await() - was before.     api.getUserInfo(token) 

UPDATE

Once I encountered a situation when downloading PDF files required removing suspend in Api class. See How to download PDF file with Retrofit and Kotlin coroutines?.

like image 157
CoolMind Avatar answered Sep 21 '22 12:09

CoolMind