web-dev-qa-db-fra.com

Impossible de créer un adaptateur d'appel pour la classe example.Simple

J'utilise retrofit 2.0.0-beta1 avec SimpleXml. Je souhaite récupérer une ressource Simple (XML) à partir d'un service REST . La gestion/suppression de l'objet Simple avec SimpleXML fonctionne correctement.

Lorsque vous utilisez ce code (code converti avant 2.0.0):

final Retrofit rest = new Retrofit.Builder()
    .addConverterFactory(SimpleXmlConverterFactory.create())
    .baseUrl(endpoint)
    .build();
SimpleService service = rest.create(SimpleService.class);
LOG.info(service.getSimple("572642"));

Un service:

public interface SimpleService {

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

}

Je reçois cette exception:

Exception in thread "main" Java.lang.IllegalArgumentException: Unable to create call adapter for class example.Simple
    for method SimpleService.getSimple
    at retrofit.Utils.methodError(Utils.Java:201)
    at retrofit.MethodHandler.createCallAdapter(MethodHandler.Java:51)
    at retrofit.MethodHandler.create(MethodHandler.Java:30)
    at retrofit.Retrofit.loadMethodHandler(Retrofit.Java:138)
    at retrofit.Retrofit$1.invoke(Retrofit.Java:127)
    at com.Sun.proxy.$Proxy0.getSimple(Unknown Source)

Qu'est-ce que je rate? Je sais que l’emballage du type de retour par un Call fonctionne. Mais je veux que le service retourne les objets métier en tant que type (et fonctionne en mode synchronisation).

METTRE À JOUR

Après avoir ajouté les dépendances supplémentaires et .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) comme suggéré par différentes réponses, j'obtiens toujours l'erreur suivante:

Caused by: Java.lang.IllegalArgumentException: Could not locate call adapter for class simple.Simple. Tried:
 * retrofit.RxJavaCallAdapterFactory
 * retrofit.DefaultCallAdapter$1
59
rmuller

Réponse courte: return Call<Simple> dans votre interface de service.

Il semblerait que Retrofit 2.0 tente de trouver un moyen de créer l’objet proxy pour votre interface de service. Il s'attend à ce que vous écriviez ceci:

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

Cependant, il veut toujours jouer à Nice et faire preuve de souplesse lorsque vous ne voulez pas renvoyer une Call. Pour supporter cela, il a le concept de CallAdapter , qui est supposé savoir comment adapter un Call<Simple> en un Simple.

L'utilisation de RxJavaCallAdapterFactory n'est utile que si vous essayez de renvoyer rx.Observable<Simple>.

La solution la plus simple consiste à renvoyer une Call comme prévu. Vous pouvez aussi écrire un CallAdapter.Factory si vous en avez vraiment besoin.

41
Hosam Aly

ajouter des dépendances:

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'

créez votre adaptateur de cette façon:

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

addCallAdapterFactory () et addConverterFactory () doivent être appelés.

Un service:

public interface SimpleService {

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

}

Modifiez Simple en Call<Simple>.

52
shichaohui

Avec le nouveau Retrofit (2. +), vous devez ajouter addCallAdapterFactory, qui peut être un normal ou un RxJavaCallAdapterFactory (pour Observables). Je pense que vous pouvez ajouter plus que les deux aussi. Il vérifie automatiquement lequel utiliser. Voir un exemple de travail ci-dessous. Vous pouvez également vérifier ce lien pour plus de détails. 

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

Ajoutez les dépendances suivantes pour la modification 2

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

pour GSON

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

pour les observables

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

Dans votre cas pour XML, vous devez inclure les dépendances suivantes

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

Mettez à jour l'appel de service comme ci-dessous 

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

Si vous voulez utiliser retrofit2 et que vous ne voulez pas toujours renvoyer retrofit2.Call<T>, vous devez créer votre propre CallAdapter.Factory qui renvoie le type simple comme prévu. Le code simple peut ressembler à ceci:

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
                }
            }
        };
    }
}

Dans ce cas, il vous suffit d’enregistrer la variable SynchronousCallAdapterFactory dans Retrofit pour résoudre votre problème.

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

Après cela, vous pouvez retourner un type simple sans retrofit2.Call.

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

dans mon cas en utilisant cette 

compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'

avec ça 

new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())...

résolu le problème quand rien d'autre ne fonctionnait

5
Hüseyin Bülbül

Pour que les exemples d’appel soient plus clairs pour les personnes qui migrent sans utiliser Rx ou qui souhaitent des appels synchrones - Call remplace essentiellement (encapsule) Response, ce qui signifie:

Response<MyObject> createRecord(...);

devient 

Call<MyObject> createRecord(...);

et pas 

Call<Response<MyObject>> createRecord(...);

(qui nécessitera encore un adaptateur)


L’appel vous permettra ensuite d’utiliser toujours isSuccessful car il renvoie une réponse. Ainsi, vous pouvez faire quelque chose comme:

myApi.createRecord(...).execute().isSuccessful()

Ou accédez à votre type (MyObject) comme:

MyObject myObj = myApi.createRecord(...).execute().body();
1
Nick Cardoso

Si vous n'utilisez pas RxJava, cela n'a aucun sens d'ajouter RxJava uniquement pour la modernisation. 2.5.0 supporte CompletableFuture intégré que vous pouvez utiliser sans ajouter aucune autre bibliothèque ou adaptateur.

build.gradle.kts

implementation("com.squareup.retrofit2:retrofit:2.5.0")
implementation("com.squareup.retrofit2:retrofit-converters:2.5.0")

Api.kt

interface Api {
    @GET("/resource")
    fun listCompanies(): CompletableFuture<ResourceDto>
}

Usage:

Retrofit.Builder()
   .addConverterFactory(SimpleXmlConverterFactory.create())
   .baseUrl("https://api.example.com")
   .build()
   .create(Api::class.Java)
1
Johannes Barop

Dans mon cas j'ai utilisé 

com.squareup.retrofit2:adapter-rxjava:2.5.0 //notice rxjava

au lieu de 

com.squareup.retrofit2:adapter-rxjava2:2.5.0 //notice rxjava2

vous devriez utiliser com.squareup.retrofit2:adapter-rxjava2:2.5.0 lorsque vous utilisez io.reactivex.rxjava2

0
svkaka

Vous pouvez implémenter un rappel, obtenir la fonction simple de onResponse.

public class MainActivity extends Activity implements Callback<Simple> {

    protected void onCreate(Bundle savedInstanceState) {
        final Retrofit rest = new Retrofit.Builder()
                    .addConverterFactory(SimpleXmlConverterFactory.create())
                    .baseUrl(endpoint)
                    .build();
        SimpleService service = rest.create(SimpleService.class);
        Call<Simple> call = service.getSimple("572642");
        //asynchronous call
        call.enqueue(this);

        return true;
    }

    @Override
    public void onResponse(Response<Simple> response, Retrofit retrofit) {
       // response.body() has the return object(s)
    }

    @Override
    public void onFailure(Throwable t) {
        // do something
    }

}
0
Sithu
public interface SimpleService {

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

}

La communication avec le réseau se fait avec le fil séparé, vous devriez donc changer votre Simple avec ça.

public interface SimpleService {

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

}
0
Syed Waqas