Używam retrofitu 2.0.0-beta1 z SimpleXml. Chcę pobrać zasób Simple (XML) z usługi REST. Marshalling / Unmarshalling obiektu Simple za pomocą SimpleXML działa dobrze.
W przypadku korzystania z tego kodu (przekonwertowanego z kodu sprzed 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"));
Usługa:
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
Mam ten wyjątek:
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)
Czego mi brakuje? Wiem, że zawijanie typu powrotu przez a Call
działa. Ale chcę, aby usługa zwracała obiekty biznesowe jako typ (i działała w trybie synchronizacji).
AKTUALIZACJA
Po dodaniu dodatkowych zależności i .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
zgodnie z sugestiami różnych odpowiedzi nadal otrzymuję ten błąd:
Caused by: java.lang.IllegalArgumentException: Could not locate call adapter for class simple.Simple. Tried:
* retrofit.RxJavaCallAdapterFactory
* retrofit.DefaultCallAdapter$1
java
rest
retrofit
simple-framework
rmuller
źródło
źródło
Odpowiedzi:
Krótka odpowiedź: wróć
Call<Simple>
do interfejsu usługi.Wygląda na to, że Retrofit 2.0 próbuje znaleźć sposób na utworzenie obiektu proxy dla interfejsu usługi. Oczekuje, że napiszesz to:
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
Jednak nadal chce grać dobrze i być elastycznym, gdy nie chcesz zwracać pliku
Call
. Aby to wesprzeć, ma koncepcję aCallAdapter
, która ma wiedzieć, jak dostosować aCall<Simple>
doSimple
.Użycie
RxJavaCallAdapterFactory
jest przydatne tylko wtedy, gdy próbujesz wrócićrx.Observable<Simple>
.Najprostszym rozwiązaniem jest zwrócenie
Call
zgodnie z oczekiwaniami Retrofit. Możesz też napisać,CallAdapter.Factory
jeśli naprawdę tego potrzebujesz.źródło
Call<Simple>
tak to działa. Jednak, jak napisałem w moim pytaniu, wolę po prostu wrócićSimple
(tak jak to miało miejsce we wcześniejszej wersji). : nie jest możliwe bez dodatkowego koduCall<Simple>
jest uszkodzony. Do jakiego pakietuSimple
należy?Simple
to klasa, o której mowa w pytaniu PO. Link toCall<T>
.W przypadku Kotlina i coroutinesów taka sytuacja miała miejsce, gdy zapomniałem oznaczyć funkcję usługi API tak, jak wywołuję
suspend
tę funkcję zCoroutineScope(Dispatchers.IO).launch{}
:Stosowanie:
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> }
źródło
dodaj zależności:
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'
stwórz swój adapter w ten sposób:
Retrofit rest = new Retrofit.Builder() .baseUrl(endpoint) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(SimpleXmlConverterFactory.create()) .build();
addCallAdapterFactory ()
iaddConverterFactory ()
oboje muszą zostać wezwani.Usługa:
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
Zmień
Simple
naCall<Simple>
.źródło
Call
do interfejsu usługiCompletableFuture
Zobacz stackoverflow.com/questions/32269064/…Z nowym Retrofitem (2. +) musisz dodać addCallAdapterFactory, który może być normalny lub RxJavaCallAdapterFactory (dla Observables). Myślę, że możesz dodać więcej niż jedno i drugie. Automatycznie sprawdza, którego użyć. Zobacz działający przykład poniżej. Możesz również sprawdzić ten link, aby uzyskać więcej informacji.
Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build()
źródło
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
com.squareup.retrofit2:adapter-rxjava:2.1.0
icom.squareup.retrofit2:converter-gson:2.1.0
Jeśli chcesz używać
retrofit2
i nie chcesz zawsze zwracaćretrofit2.Call<T>
, musisz utworzyć własny,CallAdapter.Factory
który zwraca prosty typ zgodnie z oczekiwaniami. Prosty kod może wyglądać następująco: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 } } }; } }
Wtedy prosta rejestracja
SynchronousCallAdapterFactory
w Retrofit powinna rozwiązać twój problem.Retrofit rest = new Retrofit.Builder() .baseUrl(endpoint) .addConverterFactory(SimpleXmlConverterFactory.create()) .addCallAdapterFactory(SynchronousCallAdapterFactory.create()) .build();
Następnie możesz zwrócić prosty typ bez
retrofit2.Call
.public interface SimpleService { @GET("/simple/{id}") Simple getSimple(@Path("id") String id); }
źródło
2.0.0-beta3
był to interfejs, teraz w wersji2.1.0
jest to klasa. Zredagowałem swój kod, żeby był bardziej aktualny. Dzięki.Simple getSimple()
iResponse<Simple> getSimple()
żądań: github.com/jaredsburrows/retrofit2-synchronous-adapter .Dodaj następujące zależności dla modernizacji 2
compile 'com.squareup.retrofit2:retrofit:2.1.0'
dla GSON
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
dla obserwacji
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
W twoim przypadku dla XML, musisz uwzględnić następujące zależności
compile 'com.squareup.retrofit2:converter-simplexml:2.1.0'
Zaktualizuj zgłoszenie serwisowe, jak poniżej
final Retrofit rest = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(SimpleXmlConverterFactory.create()) .baseUrl(endpoint) .build(); SimpleService service = rest.create(SimpleService.class);
źródło
w moim przypadku używając tego
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
z tym
new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())...
rozwiązał problem, gdy nic innego nie działało
źródło
Jeśli nie używasz RxJava, nie ma sensu dodawać RxJava tylko do modernizacji.
2.5.0
maCompletableFuture
wbudowaną obsługę, z której można korzystać bez dodawania innej biblioteki lub adaptera.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> }
Stosowanie:
Retrofit.Builder() .addConverterFactory(SimpleXmlConverterFactory.create()) .baseUrl("https://api.example.com") .build() .create(Api::class.java)
źródło
IllegalArgumentException: nie można utworzyć adaptera wywołań dla klasy java.lang.Object
Krótka odpowiedź: rozwiązałem to poprzez następujące zmiany
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"
Powodzenia
źródło
Aby wyjaśnić przykłady połączeń dla osób, które migrują, nie używają Rx lub chcą połączeń synchronicznych - Call zasadniczo zastępuje (zawija) odpowiedź, co oznacza:
Response<MyObject> createRecord(...);
staje się
Call<MyObject> createRecord(...);
i nie
(który nadal będzie wymagał adaptera)
Wezwanie pozwoli ci wtedy nadal używać,
isSuccessful
ponieważ w rzeczywistości zwraca odpowiedź. Możesz więc zrobić coś takiego:Lub uzyskaj dostęp do swojego Type (MyObject), na przykład:
źródło
public interface SimpleService { @GET("/simple/{id}") Simple getSimple(@Path("id") String id); }
Komunikacja z siecią odbywa się za pomocą osobnego wątku, więc powinieneś zmienić swój Simple.
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
źródło
W moim przypadku użyłem
com.squareup.retrofit2:adapter-rxjava:2.5.0 //notice rxjava
zamiast
com.squareup.retrofit2:adapter-rxjava2:2.5.0 //notice rxjava2
powinieneś używać
com.squareup.retrofit2:adapter-rxjava2:2.5.0
podczas używaniaio.reactivex.rxjava2
źródło
Możesz zaimplementować Callback, pobrać funkcję Simple from 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 } }
źródło
Sposób, w jaki naprawiłem ten problem, polegał na dodaniu tego do pliku oceny aplikacji, jeśli konfiguracja nie jest ustawiona, będą konflikty, być może zostanie to naprawione w stabilnej wersji biblioteki:
configurations { compile.exclude group: 'stax' compile.exclude group: 'xpp3' } dependencies { compile 'com.squareup.retrofit:retrofit:2.0.0-beta1' compile 'com.squareup.retrofit:converter-simplexml:2.0.0-beta1' }
i stwórz swój adapter w ten sposób:
Retrofit retrofit = new Retrofit.Builder() .baseUrl(endPoint) .addConverterFactory(SimpleXmlConverterFactory.create()) .build();
Mam nadzieję, że to pomoże!
źródło