SimpleXmlでretrofit 2.0.0-beta1を使用しています。 RESTサービスからシンプル(XML)リソースを取得したい。 SimpleXMLを使用したSimpleオブジェクトのマーシャリング/アンマーシャリングは正常に機能します。
このコードを使用する場合(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"));
サービス:
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
私はこの例外を受け取ります:
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)
何が欠けていますか?戻り値の型をCall
でラップすると機能することを知っています。しかし、サービスがビジネスオブジェクトをタイプとして返す(および同期モードで動作する)ようにしたいのです。
UPDATE
別の回答で示唆されているように、余分な依存関係と.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
を追加した後、このエラーが表示されます。
Caused by: Java.lang.IllegalArgumentException: Could not locate call adapter for class simple.Simple. Tried:
* retrofit.RxJavaCallAdapterFactory
* retrofit.DefaultCallAdapter$1
短い答え:サービスインターフェイスで Call<Simple>
を返します。
Retrofit 2.0は、サービスインターフェイスのプロキシオブジェクトを作成する方法を探しているようです。これを書くことを期待しています:
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}
ただし、Call
を返したくない場合は、引き続きNiceを再生し、柔軟にしたいです。これをサポートするために、 CallAdapter
の概念があり、これはCall<Simple>
をSimple
に適応させる方法を知っているはずです。
RxJavaCallAdapterFactory
の使用は、rx.Observable<Simple>
を返そうとする場合にのみ役立ちます。
最も簡単な解決策は、Retrofitが期待するようにCall
を返すことです。本当に必要な場合は、 CallAdapter.Factory
と書くこともできます。
依存関係を追加します。
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'
この方法でアダプターを作成します。
Retrofit rest = new Retrofit.Builder()
.baseUrl(endpoint)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
addCallAdapterFactory ()
とaddConverterFactory ()
の両方を呼び出す必要があります。
サービス:
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}
Simple
をCall<Simple>
に変更します。
新しいRetrofit(2. +)を使用すると、addCallAdapterFactoryを追加する必要があります。これは、通常のものまたはRxJavaCallAdapterFactory(for Observables)にすることができます。両方よりも多く追加できると思います。使用するものを自動的にチェックします。以下の作業例を参照してください。詳細については、 このリンク を確認することもできます。
Retrofit retrofit = new Retrofit.Builder().baseUrl(ApiConfig.BASE_URL)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build()
retrofit2
を使用し、常にretrofit2.Call<T>
を返したくない場合は、予想どおり単純型を返す独自のCallAdapter.Factory
を作成する必要があります。単純なコードは次のようになります。
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
}
}
};
}
}
その後、RetrofitでSynchronousCallAdapterFactory
を登録するだけで問題が解決するはずです。
Retrofit rest = new Retrofit.Builder()
.baseUrl(endpoint)
.addConverterFactory(SimpleXmlConverterFactory.create())
.addCallAdapterFactory(SynchronousCallAdapterFactory.create())
.build();
その後、retrofit2.Call
なしで単純型を返すことができます。
public interface SimpleService {
@GET("/simple/{id}")
Simple getSimple(@Path("id") String id);
}
レトロフィット2に次の依存関係を追加します
compile 'com.squareup.retrofit2:retrofit:2.1.0'
gSONの
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
オブザーバブル用
compile 'com.squareup.retrofit2:adapter-rxjava:2.1.0'
XMLの場合、次の依存関係を含める必要があります。
compile 'com.squareup.retrofit2:converter-simplexml:2.1.0'
サービスコールを以下のように更新します
final Retrofit rest = new Retrofit.Builder()
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl(endpoint)
.build();
SimpleService service = rest.create(SimpleService.class);
私の場合、これを使用して
compile 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0'
これとともに
new Retrofit.Builder().addCallAdapterFactory(RxJava2CallAdapterFactory.create())...
何も機能しなかったときに問題を解決しました
Rxを使用せずに移行している人、または同期コールが必要な人のためにCallの例を明確にするために、Callは本質的にResponseを置き換えます(ラップします)。
Response<MyObject> createRecord(...);
になる
Call<MyObject> createRecord(...);
ではなく
Call<Response<MyObject>> createRecord(...);
(まだアダプターが必要です)
呼び出しは、実際に応答を返すので、isSuccessful
を引き続き使用できます。次のようなことができます:
myApi.createRecord(...).execute().isSuccessful()
または、次のようにタイプ(MyObject)にアクセスします。
MyObject myObj = myApi.createRecord(...).execute().body();
RxJavaを使用していない場合、改造のためだけにRxJavaを追加することは適切ではありません。 2.5.0
にはCompletableFuture
のサポートがあり、他のライブラリやアダプターを追加せずに使用できます。
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>
}
使用法:
Retrofit.Builder()
.addConverterFactory(SimpleXmlConverterFactory.create())
.baseUrl("https://api.example.com")
.build()
.create(Api::class.Java)
私の場合、私は使用しました
com.squareup.retrofit2:adapter-rxjava:2.5.0 //notice rxjava
の代わりに
com.squareup.retrofit2:adapter-rxjava2:2.5.0 //notice rxjava2
com.squareup.retrofit2:adapter-rxjava2:2.5.0
を使用する場合は、io.reactivex.rxjava2
を使用する必要があります
コールバックを実装し、onResponse関数からSimpleを取得できます。
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);
}
ネットワークとの通信は別のスレッドで行われるため、それでSimpleを変更する必要があります。
public interface SimpleService {
@GET("/simple/{id}")
Call<Simple> getSimple(@Path("id") String id);
}