클래스 예제에 대한 호출 어댑터를 만들 수 없습니다.


87

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작품으로 포장하는 것을 알고 있습니다. 그러나 서비스가 비즈니스 개체를 유형으로 반환하고 동기화 모드에서 작동하기를 원합니다.

최신 정보

추가 종속성을 추가하고 .addCallAdapterFactory(RxJavaCallAdapterFactory.create())다른 답변에서 제안한 대로이 오류가 계속 발생합니다.

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


Coroutine을 사용하는 사람들을 위해 @chatlanin 대답
NJ

답변:


66

짧은 대답 : Call<Simple>서비스 인터페이스로 돌아갑니다 .

Retrofit 2.0이 서비스 인터페이스에 대한 프록시 개체를 만드는 방법을 찾으려고하는 것 같습니다. 다음과 같이 작성해야합니다.

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

그러나 .NET Framework를 반환하고 싶지 않을 때 여전히 멋지게 재생되고 유연하기를 원합니다 Call. 이를 지원하기 위해, 그것은의 개념이 CallAdapter적응하는 방법을 알고 가정된다, Call<Simple>로를 Simple.

의 사용은 RxJavaCallAdapterFactory반환하려는 경우에만 유용합니다 rx.Observable<Simple>.

가장 간단한 해결책은 CallRetrofit이 예상 하는 대로 를 반환하는 것입니다. CallAdapter.Factory정말로 필요한 경우를 작성할 수도 있습니다 .


1
네, 이것은 실제로 정답입니다 :(. 나는 Call<Simple>그것이 작동하는 방식을 처음부터 알고 있습니다 . 그러나 내 질문에서 언급했듯이 내 선호는 Simple(이전 버전의 경우처럼) 반환 하는 것입니다. 내 결론은 : 추가 코드 없이는 불가능
rmuller

제공 한 링크 Call<Simple> 가 끊어졌습니다. 어떤 패키지에 Simple속합니까?
shyam

@shyam 메모에 감사드립니다. 링크를 업데이트했습니다. SimpleOP의 질문에 언급 된 클래스입니다. 링크는 Call<T>입니다.
Hosam Aly

74

Kotlin코 루틴의 경우 suspend다음에서이 함수를 호출 할 때 api 서비스 함수를 표시하는 것을 잊었을 때이 상황이 발생 했습니다 CoroutineScope(Dispatchers.IO).launch{}.

용법:

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

53

종속성 추가 :

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


7
Simple to Call <Simple> 변경이 트릭이라는 것을 알고 있습니다. 그러나 Call서비스 인터페이스에 유형을 도입하고 싶지 않습니다
rmuller


38

새로운 Retrofit (2. +)을 사용하면 addCallAdapterFactory를 추가해야합니다. 이는 일반 또는 RxJavaCallAdapterFactory (Observables 용) 일 수 있습니다. 둘 다 추가 할 수도 있다고 생각합니다. 어떤 것을 사용할 것인지 자동으로 확인합니다. 아래의 작동 예를 참조하십시오. 자세한 내용은 이 링크 를 확인할 수도 있습니다 .

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

1
훌륭한 링크! 나중에 확인합니다.
rmuller 2015-08-28

1
문서에는 여전히 RestAdapter가 있으며 Retrofit 2.0으로 가장 간단한 요청을 만드는 방법에 대한 예가 없습니다. RxJavaCallAdapterFactory를 해결할 수 없다는 오류가 발생합니다. 가장 간단한 Android http 요청을 만드는 데 몇 시간이 걸렸습니다. 광고만큼 간단하지 않은 것 같습니다. 아마도 그들은 조금 더 문서화해야 할 것입니다.
Vlado Pandžić 2015-08-30

Retrofit 2.0을 사용하는 경우 RestAdapter 대신 Retrofit을 사용하십시오.
Himanshu Virmani

5
RxJavaCallAdapterFactory에는 동일한 저장소의 adapter-rxjava 아티팩트가 필요합니다. compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
Damien Diehl

3
retrofit2에 대한 올바른 종속성을 사용할 수 있도록 com.squareup.retrofit2:adapter-rxjava:2.1.0하고 com.squareup.retrofit2:converter-gson:2.1.0
조지 파파

16

사용을 원 retrofit2하고 항상 return을 원하지 않는 경우 예상대로 간단한 유형을 반환하는 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
                }
            }
        };
    }
}

그런 다음 SynchronousCallAdapterFactoryRetrofit에 등록하면 문제가 해결됩니다.

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

감사합니다. 비동기 통화 어댑터를 만드는 방법이 있는지 알고 있습니까? 그래서 다음과 같은 서비스를 호출 할 수 있습니다 : enqueue ()와 콜백을 사용하는 대신 service.getSimple ( "id", new Adapter () {onFail () {} onSuccess () {}}?
markov00

"CallAdapter.Factory 구현"이것은 인터페이스가 아닌 클래스입니까?
ozmank

@ozmank 버전에서는 2.0.0-beta3인터페이스 였지만 이제 버전 2.1.0에서는 클래스입니다. 좀 더 실제적으로 코드를 편집했습니다. 감사.
Mateusz Korwel 16. 9.

@MateuszKorwel 항상 새로운 RuntimeException (e)을 던집니다! Simple 대신 String을 반환하고 싶습니다.
Dr.jacky

3
게시 해 주셔서 감사합니다. 이 처리 Simple getSimple()Response<Simple> getSimple()요청에 대한 라이브러리를 만들었습니다 . github.com/jaredsburrows/retrofit2-synchronous-adapter .
Jared Burrows

13

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

이것은 내 설정과 동일합니다.
rmuller 2015 년

1
또한 어댑터를 만들 때 다음 줄을 추가해야합니다. .addCallAdapterFactory (RxJavaCallAdapterFactory.create ())
Shayan_Aryan

com.squareup.retrofit : 해결에 실패 어댑터 rxjava : 2.1.0은
ozmank

1
@ozmank its retrofit2, 나는 내 대답도 업데이트했습니다. 그것을 시도하십시오
rahulrv

4

제 경우에는 이것을 사용하여

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

이것으로

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

아무것도 작동하지 않을 때 문제를 해결했습니다.


2

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)

2

IllegalArgumentException : 클래스 java.lang.Object에 대한 호출 어댑터를 작성할 수 없습니다.

짧은 대답 : 다음 변경 사항으로 해결했습니다.

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"

행운을 빕니다


1

마이그레이션 중이거나 Rx를 사용하지 않는 사용자 또는 동기 호출을 원하는 사용자를 위해 Call 예제를 더 명확하게 만들기 위해 Call은 기본적으로 응답을 대체 (래핑)합니다.

Response<MyObject> createRecord(...);

된다

Call<MyObject> createRecord(...);

그리고 아닙니다

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

(아직 어댑터가 필요함)


그러면 호출이 isSuccessful실제로 응답을 반환하므로 계속 사용할 수 있습니다 . 따라서 다음과 같이 할 수 있습니다.

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

또는 다음과 같이 유형 (MyObject)에 액세스합니다.

MyObject myObj = myApi.createRecord(...).execute().body();

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

}

1

제 경우에는

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


0

콜백을 구현하고 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
    }

}

-2

이 문제를 해결 한 방법은이를 응용 프로그램 gradle 파일에 추가하는 것입니다. 구성이 설정되지 않은 경우 충돌이 발생하며 라이브러리의 안정적인 릴리스에서 수정 될 수 있습니다.

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

다음과 같이 어댑터를 만듭니다.

  Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(endPoint)
            .addConverterFactory(SimpleXmlConverterFactory.create())
            .build();

도움이 되었기를 바랍니다.


1
이것은 내 질문과 똑같은 구성입니다. 그래서, 아무것도 해결하지 않습니다 :)
rmuller
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.