Estou usando o retrofit 2.0.0-beta1 com SimpleXml. Quero recuperar um recurso Simples (XML) de um serviço REST. Marshalling / Unmarshalling o objeto Simple com SimpleXML funciona bem.
Ao usar este código (formato convertido antes do código 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"));
Serviço:
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
Eu recebo esta exceção:
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)
O que estou perdendo? Eu sei que envolver o tipo de retorno por uma Call
funciona. Mas eu quero que o serviço retorne objetos de negócios como tipo (e trabalhando em modo de sincronização).
ATUALIZAR
Depois de adicionar as dependências extras e .addCallAdapterFactory(RxJavaCallAdapterFactory.create())
conforme sugerido por diferentes respostas, ainda recebo este erro:
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
fonte
fonte
Respostas:
Resposta curta: retorne
Call<Simple>
em sua interface de serviço.Parece que o Retrofit 2.0 está tentando encontrar uma maneira de criar o objeto proxy para sua interface de serviço. Ele espera que você escreva isto:
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
No entanto, ele ainda quer jogar bem e ser flexível quando você não quiser devolver um
Call
. Para apoiar isso, ele tem o conceito de aCallAdapter
, que deve saber como adaptar aCall<Simple>
em aSimple
.O uso de
RxJavaCallAdapterFactory
só é útil se você estiver tentando retornarrx.Observable<Simple>
.A solução mais simples é retornar um
Call
como o Retrofit espera. Você também pode escrever umCallAdapter.Factory
se realmente precisar.fonte
Call<Simple>
é assim que funciona. No entanto, conforme declarado na minha pergunta, minha preferência é apenas retornarSimple
(como era o caso na versão anterior). Minha conclusão é : não é possível sem código extra.Call<Simple>
está quebrado. A qual pacoteSimple
pertence?Simple
é a classe mencionada na pergunta do OP. O link é paraCall<T>
.No caso de Kotlin e corrotinas, essa situação aconteceu quando eu esqueci de marcar a função de serviço da API como
suspend
quando chamo essa função deCoroutineScope(Dispatchers.IO).launch{}
:Uso:
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> }
fonte
adicionar dependências:
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'
crie seu adaptador desta forma:
Retrofit rest = new Retrofit.Builder() .baseUrl(endpoint) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(SimpleXmlConverterFactory.create()) .build();
addCallAdapterFactory ()
eaddConverterFactory ()
ambos precisam ser chamados.Serviço:
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
Modifique
Simple
paraCall<Simple>
.fonte
Call
à interface de serviçoCompletableFuture
Ver stackoverflow.com/questions/32269064/…Com o novo Retrofit (2. +), você precisa adicionar addCallAdapterFactory que pode ser normal ou RxJavaCallAdapterFactory (para Observables). Acho que você também pode adicionar mais do que ambos. Ele verifica automaticamente qual usar. Veja um exemplo de trabalho abaixo. Você também pode verificar este link para mais detalhes.
Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConfig.BASE_URL) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .build()
fonte
compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
com.squareup.retrofit2:adapter-rxjava:2.1.0
ecom.squareup.retrofit2:converter-gson:2.1.0
Se quiser usar
retrofit2
e não quiser retornar sempreretrofit2.Call<T>
, você deve criar o seu próprioCallAdapter.Factory
tipo simples de retorno conforme o esperado. O código simples pode ter a seguinte aparência: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 } } }; } }
Então, basta registrar-se
SynchronousCallAdapterFactory
no Retrofit para resolver seu problema.Retrofit rest = new Retrofit.Builder() .baseUrl(endpoint) .addConverterFactory(SimpleXmlConverterFactory.create()) .addCallAdapterFactory(SynchronousCallAdapterFactory.create()) .build();
Depois disso, você pode retornar um tipo simples sem
retrofit2.Call
.public interface SimpleService { @GET("/simple/{id}") Simple getSimple(@Path("id") String id); }
fonte
2.0.0-beta3
era uma interface, agora na versão2.1.0
é uma classe. Eu editei meu código, para ser mais atual. Obrigado.Simple getSimple()
eResponse<Simple> getSimple()
solicitações: github.com/jaredsburrows/retrofit2-synchronous-adapter .Adicione as seguintes dependências para retrofit 2
compile 'com.squareup.retrofit2:retrofit:2.1.0'
para GSON
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
para observáveis
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
No seu caso para XML, você teria que incluir as seguintes dependências
compile 'com.squareup.retrofit2:converter-simplexml:2.1.0'
Atualize a chamada de serviço conforme abaixo
final Retrofit rest = new Retrofit.Builder() .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) .addConverterFactory(SimpleXmlConverterFactory.create()) .baseUrl(endpoint) .build(); SimpleService service = rest.create(SimpleService.class);
fonte
no meu caso usar isso
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
com isso
new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())...
resolveu o problema quando nada mais funcionava
fonte
Se você não estiver usando o RxJava corretamente, não faz sentido adicionar o RxJava apenas para atualização.
2.5.0
tem suporte paraCompletableFuture
built-in que você pode usar sem adicionar qualquer outra biblioteca ou adaptador.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> }
Uso:
Retrofit.Builder() .addConverterFactory(SimpleXmlConverterFactory.create()) .baseUrl("https://api.example.com") .build() .create(Api::class.java)
fonte
IllegalArgumentException: Não é possível criar um adaptador de chamada para a classe java.lang.Object
Resposta curta: Resolvi com as seguintes mudanças
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"
Boa sorte
fonte
Apenas para tornar os exemplos de chamada mais claros para pessoas que estão migrando, não usando Rx ou que desejam chamadas síncronas - a chamada essencialmente substitui (envolve) a resposta, o que significa:
Response<MyObject> createRecord(...);
torna-se
Call<MyObject> createRecord(...);
e não
(que ainda exigirá um adaptador)
A Chamada permitirá que você ainda use,
isSuccessful
pois ela realmente retorna uma Resposta. Então você pode fazer algo como:Ou acesse seu tipo (MyObject) como:
fonte
public interface SimpleService { @GET("/simple/{id}") Simple getSimple(@Path("id") String id); }
A comunicação com a rede é feita com o segmento separado, então você deve alterar o seu Simples com ele.
public interface SimpleService { @GET("/simple/{id}") Call<Simple> getSimple(@Path("id") String id); }
fonte
No meu caso eu usei
com.squareup.retrofit2:adapter-rxjava:2.5.0 //notice rxjava
ao invés de
com.squareup.retrofit2:adapter-rxjava2:2.5.0 //notice rxjava2
você deveria estar usando
com.squareup.retrofit2:adapter-rxjava2:2.5.0
ao usario.reactivex.rxjava2
fonte
Você pode implementar um retorno de chamada, obter a função Simples 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 } }
fonte
A maneira como eu corrigi esse problema foi adicionando isso ao arquivo gradle do aplicativo, se a configuração não for definida haverá conflitos, talvez isso seja corrigido na versão estável da biblioteca:
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' }
e crie seu adaptador desta forma:
Retrofit retrofit = new Retrofit.Builder() .baseUrl(endPoint) .addConverterFactory(SimpleXmlConverterFactory.create()) .build();
Espero que ajude!
fonte