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
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.
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>
.
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()
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);
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);
}
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
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();
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)
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
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
}
}
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);
}