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.