webentwicklung-frage-antwort-db.com.de

Aufrufadapter für Klasse example.Simple kann nicht erstellt werden

Ich benutze Retrofit 2.0.0-beta1 mit SimpleXml. Ich möchte, dass die Simple-Ressource (XML) von einem REST -Dienst abgerufen wird.

Bei Verwendung dieses Codes (konvertiertes Formular vor 2.0.0 Code):

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

Bedienung:

public interface SimpleService {

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

}

Ich bekomme diese Ausnahme:

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)

Was vermisse ich? Ich weiß, dass das Umhüllen des Rückgabetyps durch eine Call funktioniert. Ich möchte jedoch, dass der Service Geschäftsobjekte als Typ zurückgibt (und im Synchronisationsmodus arbeitet).

UPDATE

Nachdem ich die zusätzlichen Abhängigkeiten und .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) hinzugefügt habe, wie in verschiedenen Antworten vorgeschlagen, erhalte ich immer noch diesen Fehler:

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

Kurze Antwort: Geben Sie Call<Simple> in Ihre Service-Schnittstelle ein.

Offenbar versucht Retrofit 2.0, ein Proxy-Objekt für Ihre Service-Schnittstelle zu erstellen. Es erwartet, dass Sie dies schreiben:

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

Es möchte jedoch immer noch Nizza spielen und flexibel sein, wenn Sie keine Call zurückgeben möchten. Um dies zu unterstützen, hat es das Konzept einer CallAdapter , das wissen soll, wie ein Call<Simple> in eine Simple angepasst wird.

Die Verwendung von RxJavaCallAdapterFactory ist nur nützlich, wenn Sie versuchen, rx.Observable<Simple> zurückzugeben.

Die einfachste Lösung ist die Rückgabe einer Call, wie Retrofit erwartet. Sie könnten auch einen CallAdapter.Factory schreiben, wenn Sie es wirklich brauchen.

41
Hosam Aly

abhängigkeiten hinzufügen:

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'

erstellen Sie Ihren Adapter auf diese Weise:

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

addCallAdapterFactory () und addConverterFactory () müssen beide aufgerufen werden.

Bedienung:

public interface SimpleService {

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

}

Ändern Sie Simple in Call<Simple>.

52
shichaohui

Mit dem neuen Retrofit (2. +) müssen Sie addCallAdapterFactory hinzufügen. Dies kann eine normale oder eine RxJavaCallAdapterFactory (für Observables) sein. Ich denke, Sie können auch mehr als beides hinzufügen. Es prüft automatisch, welches verwendet werden soll. Siehe unten ein Arbeitsbeispiel. Sie können auch diesen Link für weitere Details überprüfen. 

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

Fügen Sie die folgenden Abhängigkeiten für die Nachrüstung hinzu 2

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

für GSON

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

für Observables

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

In Ihrem Fall für XML müssen Sie die folgenden Abhängigkeiten hinzufügen

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

Aktualisieren Sie den Serviceabruf wie folgt 

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

Wenn Sie retrofit2 verwenden möchten und nicht immer retrofit2.Call<T> zurückgeben möchten, müssen Sie einen eigenen CallAdapter.Factory erstellen, der den einfachen Typ zurückgibt, wie Sie es erwartet haben. Der einfache Code kann folgendermaßen aussehen:

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

Dann sollten Sie einfach die SynchronousCallAdapterFactory in Retrofit registrieren, um Ihr Problem zu lösen.

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

Danach können Sie einfachen Typ ohne retrofit2.Call zurückgeben.

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

in meinem Fall mit diesem 

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

mit diesem 

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

gelöst das problem wenn nichts anderes funktionierte

5

Nur um die Anrufbeispiele für Personen zu verdeutlichen, die migrieren, keinen Empfängerempfänger verwenden oder synchrone Anrufe wünschen - Anruf ersetzt im Wesentlichen (wraps) Response, dh:

Response<MyObject> createRecord(...);

wird 

Call<MyObject> createRecord(...);

und nicht 

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

(was noch einen Adapter erfordert)


Mit dem Aufruf können Sie isSuccessful weiterhin verwenden, da er tatsächlich eine Antwort zurückgibt. So kannst du so etwas tun:

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

Oder greifen Sie auf Ihren Typ (MyObject) wie folgt zu:

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

Wenn Sie RxJava nicht verwenden, ist es nicht sinnvoll, RxJava nur zum Nachrüsten hinzuzufügen. 2.5.0 unterstützt CompletableFuture, die Sie verwenden können, ohne eine andere Bibliothek oder einen anderen Adapter hinzuzufügen.

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

Verwendungszweck:

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

In meinem Fall habe ich verwendet 

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

anstatt 

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

sie sollten com.squareup.retrofit2:adapter-rxjava2:2.5.0 verwenden, wenn Sie io.reactivex.rxjava2 verwenden.

0
svkaka

Sie können einen Rückruf implementieren und die Funktion Simple from onResponse verwenden.

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

}

Die Kommunikation mit dem Netzwerk erfolgt über einen separaten Thread, daher sollten Sie Ihr Simple damit ändern.

public interface SimpleService {

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

}
0
Syed Waqas