Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to create call adapter for class example.Simple

In case of Kotlin and coroutines this situation happened when I forgot to mark api service function as suspend when I call this function from CoroutineScope(Dispatchers.IO).launch{}:

Usage:

    val apiService = RetrofitFactory.makeRetrofitService()

    CoroutineScope(Dispatchers.IO).launch {

        val response = apiService.myGetRequest()

        // process response...

    }

ApiService.kt

interface ApiService {

       @GET("/my-get-request")
       suspend fun myGetRequest(): Response<String>
}

Short answer: return Call<Simple> in your service interface.

It looks like Retrofit 2.0 is trying to find a way of creating the proxy object for your service interface. It expects you to write this:

public interface SimpleService {
    @GET("/simple/{id}")
    Call<Simple> getSimple(@Path("id") String id);
}

However, it still wants to play nice and be flexible when you don't want to return a Call. To support this, it has the concept of a CallAdapter, which is supposed to know how to adapt a Call<Simple> into a Simple.

The use of RxJavaCallAdapterFactory is only useful if you are trying to return rx.Observable<Simple>.

The simplest solution is to return a Call as Retrofit expects. You could also write a CallAdapter.Factory if you really need it.


add dependencies:

compile 'com.squareup.retrofit:retrofit:2.0.0-beta1'
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
compile 'com.squareup.retrofit:converter-gson:2.0.0-beta1'

create your adapter this way:

Retrofit rest = new Retrofit.Builder()
    .baseUrl(endpoint)
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .addConverterFactory(SimpleXmlConverterFactory.create())
    .build();

addCallAdapterFactory () and addConverterFactory () both need to be called.

Service:

public interface SimpleService {

    @GET("/simple/{id}")
    Call<Simple> getSimple(@Path("id") String id);

}

Modify Simple to Call<Simple>.


With the new Retrofit(2.+) you need to add addCallAdapterFactory which can be a normal one or a RxJavaCallAdapterFactory(for Observables). I think you can add more than both too. It automatically checks which one to use. See a working example below. You can also check this link for more details.

 Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConfig.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
        .build()

If you want use retrofit2 and you don't want always return retrofit2.Call<T>, you have to create your own CallAdapter.Factory which return simple type as you expected. The simple code can look like this:

import retrofit2.Call;
import retrofit2.CallAdapter;
import retrofit2.Retrofit;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;

public class SynchronousCallAdapterFactory extends CallAdapter.Factory {
    public static CallAdapter.Factory create() {
        return new SynchronousCallAdapterFactory();
    }

    @Override
    public CallAdapter<Object, Object> get(final Type returnType, Annotation[] annotations, Retrofit retrofit) {
        // if returnType is retrofit2.Call, do nothing
        if (returnType.toString().contains("retrofit2.Call")) {
            return null;
        }

        return new CallAdapter<Object, Object>() {
            @Override
            public Type responseType() {
                return returnType;
            }

            @Override
            public Object adapt(Call<Object> call) {
                try {
                    return call.execute().body();
                } catch (Exception e) {
                    throw new RuntimeException(e); // do something better
                }
            }
        };
    }
}

Then simple register the SynchronousCallAdapterFactory in Retrofit should solved your problem.

Retrofit rest = new Retrofit.Builder()
        .baseUrl(endpoint)
        .addConverterFactory(SimpleXmlConverterFactory.create())
        .addCallAdapterFactory(SynchronousCallAdapterFactory.create())
        .build();

After that you can return simple type without retrofit2.Call.

public interface SimpleService {
    @GET("/simple/{id}")
    Simple getSimple(@Path("id") String id);
}

Add the following dependencies for retrofit 2

 compile 'com.squareup.retrofit2:retrofit:2.1.0'

for GSON

 compile 'com.squareup.retrofit2:converter-gson:2.1.0'

for observables

compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'

In your case for XML , you would have to include the following dependencies

 compile 'com.squareup.retrofit2:converter-simplexml:2.1.0'

Update the service call as below

final Retrofit rest = new Retrofit.Builder()
    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
    .addConverterFactory(SimpleXmlConverterFactory.create())
    .baseUrl(endpoint)
    .build();
SimpleService service = rest.create(SimpleService.class);

IllegalArgumentException: Unable to create call adapter for class java.lang.Object

Short answer: I have solved it by the following changes

ext.retrofit2Version = '2.4.0' -> '2.6.0'
implementation"com.squareup.retrofit2:retrofit:$retrofit2Version"
implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit2Version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit2Version"

Good luck