Impossibile creare il convertitore per la mia classe nella libreria Retrofit di Android


130

Sto migrando dall'uso di Volley a Retrofit, ho già una classe gson che ho usato prima per convertire la risposta JSONObject in un oggetto che implementa le annotazioni gson. Quando provo a fare in modo che http ottenga una richiesta utilizzando il retrofit, ma la mia app si arresta in modo anomalo con questo errore:

 Unable to start activity ComponentInfo{com.lightbulb.pawesome/com.example.sample.retrofit.SampleActivity}: java.lang.IllegalArgumentException: Unable to create converter for class com.lightbulb.pawesome.model.Pet
    for method GitHubService.getResponse

Sto seguendo la guida nel sito di retrofit e ho escogitato queste implementazioni:

Questa è la mia attività in cui sto cercando di eseguire la richiesta http retro:

public class SampleActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sample);

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl("**sample base url here**")
                .build();

        GitHubService service = retrofit.create(GitHubService.class);
        Call<Pet> callPet = service.getResponse("41", "40");
        callPet.enqueue(new Callback<Pet>() {
            @Override
            public void onResponse(Response<Pet> response) {
                Log.i("Response", response.toString());
            }

            @Override
            public void onFailure(Throwable t) {
                Log.i("Failure", t.toString());
            }
        });
        try{
            callPet.execute();
        } catch (IOException e){
            e.printStackTrace();
        }

    }
}

La mia interfaccia che è diventata la mia API

public interface GitHubService {
    @GET("/ **sample here** /{petId}/{otherPet}")
    Call<Pet> getResponse(@Path("petId") String userId, @Path("otherPet") String otherPet);
}

E infine la classe Pet che dovrebbe essere la risposta:

public class Pet implements Parcelable {

    public static final String ACTIVE = "1";
    public static final String NOT_ACTIVE = "0";

    @SerializedName("is_active")
    @Expose
    private String isActive;
    @SerializedName("pet_id")
    @Expose
    private String petId;
    @Expose
    private String name;
    @Expose
    private String gender;
    @Expose
    private String age;
    @Expose
    private String breed;
    @SerializedName("profile_picture")
    @Expose
    private String profilePicture;
    @SerializedName("confirmation_status")
    @Expose
    private String confirmationStatus;

    /**
     *
     * @return
     * The confirmationStatus
     */
    public String getConfirmationStatus() {
        return confirmationStatus;
    }

    /**
     *
     * @param confirmationStatus
     * The confirmation_status
     */
    public void setConfirmationStatus(String confirmationStatus) {
        this.confirmationStatus = confirmationStatus;
    }

    /**
     *
     * @return
     * The isActive
     */
    public String getIsActive() {
        return isActive;
    }

    /**
     *
     * @param isActive
     * The is_active
     */
    public void setIsActive(String isActive) {
        this.isActive = isActive;
    }

    /**
     *
     * @return
     * The petId
     */
    public String getPetId() {
        return petId;
    }

    /**
     *
     * @param petId
     * The pet_id
     */
    public void setPetId(String petId) {
        this.petId = petId;
    }

    /**
     *
     * @return
     * The name
     */
    public String getName() {
        return name;
    }

    /**
     *
     * @param name
     * The name
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     *
     * @return
     * The gender
     */
    public String getGender() {
        return gender;
    }

    /**
     *
     * @param gender
     * The gender
     */
    public void setGender(String gender) {
        this.gender = gender;
    }

    /**
     *
     * @return
     * The age
     */
    public String getAge() {
        return age;
    }

    /**
     *
     * @param age
     * The age
     */
    public void setAge(String age) {
        this.age = age;
    }

    /**
     *
     * @return
     * The breed
     */
    public String getBreed() {
        return breed;
    }

    /**
     *
     * @param breed
     * The breed
     */
    public void setBreed(String breed) {
        this.breed = breed;
    }

    /**
     *
     * @return
     * The profilePicture
     */
    public String getProfilePicture() {
        return profilePicture;
    }

    /**
     *
     * @param profilePicture
     * The profile_picture
     */
    public void setProfilePicture(String profilePicture) {
        this.profilePicture = profilePicture;
    }


    protected Pet(Parcel in) {
        isActive = in.readString();
        petId = in.readString();
        name = in.readString();
        gender = in.readString();
        age = in.readString();
        breed = in.readString();
        profilePicture = in.readString();
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(isActive);
        dest.writeString(petId);
        dest.writeString(name);
        dest.writeString(gender);
        dest.writeString(age);
        dest.writeString(breed);
        dest.writeString(profilePicture);
    }

    @SuppressWarnings("unused")
    public static final Parcelable.Creator<Pet> CREATOR = new Parcelable.Creator<Pet>() {
        @Override
        public Pet createFromParcel(Parcel in) {
            return new Pet(in);
        }

        @Override
        public Pet[] newArray(int size) {
            return new Pet[size];
        }
    };
}

per favore aggiungi la risposta String di questo link mysample.com/development/cuteness
— koutuk

@koutuk è solo un esempio, tra l'altro ho già cambiato il mio post
— Earwin delos Santos

a quale riga stai ricevendo un errore ....
— koutuk,

dovresti andare su youtube.com/watch?v=gGuUBlzmtPQ questo video
— koutuk,

oh quello è quello vecchio. prova a visitare retrofit square.github.io/retrofit
— Earwin delos Santos

Risposte:


217

Prima 2.0.0, il convertitore predefinito era un convertitore gson, ma in 2.0.0e successivamente è il convertitore predefinito ResponseBody. Dai documenti:

Per impostazione predefinita, Retrofit può solo deserializzare i corpi HTTP nel ResponseBodytipo di OkHttp e può solo accettarne il RequestBodytipo @Body.

In 2.0.0+, devi specificare esplicitamente che desideri un convertitore Gson:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("**sample base url here**")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

Sarà inoltre necessario aggiungere la seguente dipendenza al file gradle:

compile 'com.squareup.retrofit2:converter-gson:2.1.0'

Utilizzare la stessa versione per il convertitore utilizzata per il retrofit. Quanto sopra corrisponde a questa dipendenza di retrofit:

compile ('com.squareup.retrofit2:retrofit:2.1.0')

Inoltre, nota al momento di scrivere questo, i documenti di retrofit non sono completamente aggiornati, motivo per cui quell'esempio ti ha messo nei guai. Dai documenti:

Nota: questo sito è ancora in fase di espansione per le nuove API 2.0.


sto ancora
— riscontrando

217

Se qualcuno dovesse mai imbattersi in questo in futuro perché stai cercando di definire la tua fabbrica di convertitori personalizzati e stai riscontrando questo errore, può anche essere causato dalla presenza di più variabili in una classe con un nome errato o con lo stesso nome serializzato. IE:

public class foo {
  @SerializedName("name")
  String firstName;
  @SerializedName("name")
  String lastName;
}

Avere i nomi serializzati definiti due volte (probabilmente per errore) genererà lo stesso identico errore.

Aggiornamento : tieni presente che questa logica vale anche per eredità. Se si estende a una classe genitore con un oggetto che ha lo stesso nome serializzato della classe secondaria, si verificherà lo stesso problema.


2
Questo è stato il problema per me, ho dimenticato di rimuovere un campo all'interno di una classe figlio che ho spostato nella classe genitore. Grazie uomo!
— Vucko,

1
Grazie mi hai salvato da 2 giorni di lotte. Ho fatto lo stesso errore dichiarando 2 variabili con gli stessi nomi serializzati.
— Valynk,

9

Sulla base del commento principale ho aggiornato le mie importazioni

implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'

Ho usato http://www.jsonschema2pojo.org/ per creare pojo dai risultati di Spotify json e assicurarmi di specificare il formato Gson.

In questi giorni ci sono plugin di Android Studio che possono creare per te i modelli di dati di pojo o Kotlin. Un'ottima opzione per Mac è Quicktype. https://itunes.apple.com/us/app/paste-json-as-code-quicktype/id1330801220


6

assicurati solo di non utilizzare lo stesso nome serializzato due volte

 @SerializedName("name") val name: String
 @SerializedName("name") val firstName: String

basta rimuoverne uno


Grazie, mi hai salvato la giornata :)
— Hemendra Gangwar,

era il mio problema .. Grazie a tuo fratello ...
— happy_Coding

4

Nel mio caso, avevo un oggetto TextView all'interno della mia classe modale e GSON non sapeva come serializzarlo. Contrassegnandolo come "transitorio" risolto il problema.


Mentre questo lo renderà visibile, tieni presente che non funzionerà se offuschi il codice (IE, tramite proguard) e lo pubblichi; meglio avere invece le annotazioni SerializedName o Exposed
— PGMacDesign

3

Il post di @ Silmarilos mi ha aiutato a risolvere questo problema. Nel mio caso, è stato che ho usato "id" come nome serializzato, in questo modo:

 @SerializedName("id")
var node_id: String? = null

e l'ho cambiato in

 @SerializedName("node_id")
var node_id: String? = null

Ora tutto funziona. Ho dimenticato che "id" è un attributo predefinito.


1

Questo può aiutare qualcuno

Nel mio caso per errore ho scritto SerializedName in questo modo

@SerializedName("name","time")
String name,time; 

Dovrebbe essere

@SerializedName("name")
String name;

@SerializedName("time")
String time;

0

Ehi, stavo attraversando lo stesso problema oggi mi ci è voluto un giorno intero per trovare una soluzione, ma questa è la soluzione che ho trovato finalmente. Sto usando Dagger nel mio codice e avevo bisogno di implementare il convertitore Gson nella mia istanza di retrofit.

quindi questo era il mio codice prima

@Provides
    @Singleton
    Retrofit providesRetrofit(Application application,OkHttpClient client) {
        String SERVER_URL=URL;
        Retrofit.Builder builder = new Retrofit.Builder();
        builder.baseUrl(SERVER_URL);
        return builder
                .client(client)
                .build();
    }

questo è quello che ho finito

@Provides
    @Singleton
    Retrofit providesRetrofit(Application application,OkHttpClient client, Gson gson) {
        String SERVER_URL=URL;
        Retrofit.Builder builder = new Retrofit.Builder();
        builder.baseUrl(SERVER_URL);
        return builder
                .client(client)
                .addConverterFactory(GsonConverterFactory.create(gson))
                .build();
    }

nota come non vi sia alcun convertitore nel primo esempio e l'aggiunta, se non hai istanziato Gson, la aggiungi in questo modo

    @Provides
    @Singleton
    Gson provideGson() {
        GsonBuilder gsonBuilder = new GsonBuilder();

   gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
        return gsonBuilder.create();
    }

e assicurati di averlo incluso nella chiamata del metodo per il retrofit.

spero ancora una volta che questo aiuti qualcuno come me.


0

Nel mio caso, era dovuto al tentativo di inserire un elenco restituito dal mio servizio in un elenco di array. Quindi quello che avevo era:

@Json(name = "items")
private ArrayList<ItemModel> items;

quando avrei dovuto

@Json(name = "items")
private List<ItemModel> items;

Spero che questo aiuti qualcuno!


0

Nel mio caso, il problema era che il mio modello SUPERCLASS aveva questo campo definito in esso. Molto stupido, lo so ....

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.