वर्ग उदाहरण के लिए कॉल एडाप्टर बनाने में असमर्थ


87

मैं SimpleXml के साथ रेट्रोफिट 2.0.0-बीटा 1 का उपयोग कर रहा हूं। मैं REST सेवा से एक सरल (XML) संसाधन प्राप्त करना चाहता हूं। सिंपल ऑब्जेक्ट को सिंपल एक्सएमएल के साथ मार्शल / अनमरशलिंग करना ठीक काम करता है।

इस कोड का उपयोग करते समय (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 check @chatlanin उत्तर
NJ

जवाबों:


66

संक्षिप्त उत्तर: Call<Simple>अपनी सेवा इंटरफ़ेस में लौटें ।

ऐसा लगता है कि Retrofit 2.0 आपके सेवा इंटरफ़ेस के लिए प्रॉक्सी ऑब्जेक्ट बनाने का एक तरीका खोजने की कोशिश कर रहा है। यह आपसे यह अपेक्षा करता है:

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

हालाँकि, यह तब भी अच्छा खेलना चाहता है और लचीला होना चाहिए जब आप वापस नहीं लौटना चाहते Call। इसका समर्थन करने के लिए, इसमें एक की अवधारणा है CallAdapter, जिसे यह जानना चाहिए कि कैसे एक Call<Simple>में अनुकूलित किया जाए Simple

RxJavaCallAdapterFactoryयदि आप लौटने की कोशिश कर रहे हैं तो इसका उपयोग केवल उपयोगी है rx.Observable<Simple>

सबसे सरल उपाय Callरिट्रोफिट की उम्मीद के रूप में वापस करना है। आप भी लिख सकते हैं CallAdapter.Factoryयदि आपको वास्तव में इसकी आवश्यकता है।


1
हां, यह वास्तव में सही उत्तर है :(। मैं शुरू से जानता हूं कि Call<Simple>यह जिस तरह से काम करता है। हालांकि, जैसा कि मेरे प्रश्न में कहा गया है कि मेरी प्राथमिकता सिर्फ वापसी करना है Simple(जैसा कि पहले संस्करण में मामला था) मेरा निष्कर्ष है। : बिना अतिरिक्त कोड के संभव नहीं।
rmuller

आपके द्वारा प्रदान किया गया लिंक Call<Simple> टूट गया है। किस पैकेज से Simpleसंबंधित है?
श्याम

नोट @shyam के लिए धन्यवाद। मैंने लिंक अपडेट किए हैं। Simpleओपी के प्रश्न में वर्णित वर्ग है। के लिए लिंक है Call<T>
होसम ऐली

75

के मामले में Kotlin और coroutines इस स्थिति तब हुई जब मैं के रूप में चिह्नित एपीआई सेवा कार्य करने के लिए भूल गया suspendजब मैं इस समारोह से कॉल 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
मुझे पता है कि सिंपल टू कॉल <सिंपल> को चेंज करने का काम ट्रिक करती है। हालाँकि, मैं Callसर्विस इंटरफ़ेस में टाइप शुरू नहीं करना चाहता हूँ
rmuller


38

नए Retrofit (2. +) के साथ आपको addCallAdapterFactory जोड़ने की आवश्यकता है जो एक सामान्य एक या RxJavaCallAdapterFactory (वेधशालाओं के लिए) हो सकता है। मुझे लगता है कि आप दोनों से अधिक जोड़ सकते हैं। यह स्वचालित रूप से जांच करता है कि किसका उपयोग करना है। नीचे एक कार्यशील उदाहरण देखें। अधिक जानकारी के लिए आप इस लिंक को भी देख सकते हैं ।

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

1
बढ़िया लिंक! बाद में जांच करेंगे।
rmuller

1
प्रलेखन में अभी भी रेस्टैप एडाप्टर है और कोई उदाहरण नहीं है कि रेट्रोफिट 2.0 के साथ सबसे सरल अनुरोध कैसे किया जाए। मैं त्रुटि प्राप्त RxJavaCallAdapterFactory हल नहीं कर सका। सबसे सरल Android http अनुरोध करने के लिए कुछ घंटे बिताए। ऐसा लगता है कि यह इतना आसान नहीं है क्योंकि वे विज्ञापन करते हैं। हो सकता है कि उन्हें थोड़ा और दस्तावेज़ करना चाहिए।
व्लादो पांडेसिक

यदि आप Retrofit 2.0 का उपयोग कर रहे हैं, तो RestAdapter के बजाय Retrofit का उपयोग करें।
हिमांशु विरमानी

5
RxJavaCallAdapterFactory को उसी रेपो से एडेप्टर-आरएक्सजैवा विरूपण साक्ष्य की आवश्यकता होती है। compile 'com.squareup.retrofit:adapter-rxjava:2.0.0-beta1'
डेमियन डाईहाल

3
Retrofit2 के लिए, सुनिश्चित करें कि आप सही निर्भरता का उपयोग करते हैं com.squareup.retrofit2:adapter-rxjava:2.1.0और com.squareup.retrofit2:converter-gson:2.1.0
जॉर्ज पापास

16

यदि आप उपयोग करना चाहते हैं 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
                }
            }
        };
    }
}

फिर 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);
}

बहुत अच्छे धन्यवाद। क्या आप जानते हैं कि क्या कोई एस्क्लाइन कॉल एडॉप्टर बनाने का कोई तरीका है? इसलिए मैं उस तरह की सेवा को कॉल कर सकता हूं: service.getSimple ("id", नया एडेप्टर () {onFail () {} onSuccess () {}} के बजाय enqueue () और कॉलबैक का उपयोग करें?
markov00

"कॉल-अडैप्टर.एक्टिफिकेशन लागू करता है" यह एक वर्ग है जो एक इंटरफ़ेस नहीं है?
ओजमंक

@ozmank संस्करण में 2.0.0-beta3यह एक इंटरफ़ेस था, अब संस्करण में 2.1.0यह एक वर्ग है। मैंने अपना कोड संपादित किया, और अधिक वास्तविक होने के लिए। धन्यवाद।
माटूस कोर्वेल

@MateuszKorwel यह हमेशा नई RuntimeException (e) फेंकना मिलता है! मैं सिंपल के बजाय स्ट्रिंग लौटना चाहता हूं।
डॉ। अंजी

3
धन्यवाद इस पोस्ट करने के लिए। मैंने इस हैंडलिंग Simple getSimple()और Response<Simple> getSimple()अनुरोधों के आसपास एक पुस्तकालय बनाया है : github.com/jaredsburrows/retrofit2-synchronous-adcape
जारेड बरोज

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

1
एडेप्टर बनाते समय इस लाइन को जोड़ना भी सुनिश्चित करें: .addCallAdapterFactory (RxJavaCallAdapterFactory.create ())
Shayan_Aryan

हल करने में विफल: com.squareup.retrofit: adapter-rxjava: 2.1.0
ozmank

1
@ozmank ने अपना रेट्रोफिट 2, मैंने अपना उत्तर भी अपडेट कर दिया है। कृपया इसे
आजमाएँ

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 का उपयोग नहीं कर रहे हैं, या जो तुल्यकालिक कॉल चाहते हैं - कॉल अनिवार्य रूप से बदलता है (रैप्स) प्रतिक्रिया, अर्थ:

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

}

नेटवर्क के साथ संचार अलग थ्रेड के साथ किया जाता है, इसलिए आपको उसके साथ अपना सिंपल बदलना चाहिए।

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

आप कॉलबैक को कार्यान्वित कर सकते हैं, ऑनरस्पेस फ़ंक्शन से सरल प्राप्त कर सकते हैं।

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

जिस तरह से मैंने इस मुद्दे को तय किया है, वह इसे एप्लिकेशन ग्रेडल फ़ाइल में जोड़ रहा था, अगर कॉन्फ़िगरेशन सेट नहीं है, तो संघर्ष होगा, शायद यह लाइब्रेरी की स्थिर रिलीज़ में तय किया जाएगा:

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
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.