Konverter für meine Klasse in der Android Retrofit-Bibliothek kann nicht erstellt werden


129

Bei der Migration von Volley zu Retrofit habe ich bereits eine gson-Klasse, die ich zuvor zum Konvertieren der JSONObject-Antwort in ein Objekt verwendet habe, das gson-Annotationen implementiert. Wenn ich versuche, http mithilfe von Nachrüsten anzufordern, meine App jedoch mit folgendem Fehler abstürzt:

 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

Ich folge der Anleitung auf der Nachrüstseite und habe mir diese Implementierungen ausgedacht:

Dies ist meine Aktivität, bei der ich versuche, die Retro-http-Anforderung auszuführen:

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

    }
}

Meine Schnittstelle, die sich als meine API herausstellte

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

Und schließlich die Pet-Klasse, die die Antwort sein sollte:

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

Bitte fügen Sie die Antwort Zeichenfolge
koutuk

@ Koutuk, das ist nur ein Beispiel, übrigens habe ich meinen Beitrag bereits geändert
Earwin delos Santos

an welcher Zeile Sie Fehler bekommen ....
Koutuk

Sie sollten durch youtube.com/watch?v=gGuUBlzmtPQ dieses Video gehen
koutuk

ohh das ist der alte. versuchen Sie, retrofit square.github.io/retrofit
Earwin delos Santos

Antworten:


217

Vor 2.0.0war der Standardkonverter ein Gson Konverter, aber in 2.0.0und später der Standard - Konverter ist ResponseBody. Aus den Dokumenten:

Standardmäßig kann Retrofit HTTP-Körper nur in den ResponseBodyTyp von OkHttp deserialisieren und nur den RequestBodyTyp für akzeptieren @Body.

In 2.0.0+müssen Sie explizit angeben, dass Sie einen Gson-Konverter möchten:

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

Sie müssen Ihrer Gradle-Datei auch die folgende Abhängigkeit hinzufügen:

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

Verwenden Sie für den Konverter dieselbe Version wie für Ihre Nachrüstung. Das Obige entspricht dieser Nachrüstungsabhängigkeit:

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

Beachten Sie außerdem, dass die Nachrüstdokumente zum Zeitpunkt des Schreibens nicht vollständig aktualisiert wurden, weshalb Sie in diesem Beispiel in Schwierigkeiten geraten sind. Aus den Dokumenten:

Hinweis: Diese Site wird derzeit für die neuen 2.0-APIs erweitert.


Ich habe immer noch das Problem
user3475052

215

Wenn jemand in Zukunft darauf stößt, weil Sie versuchen, Ihre eigene benutzerdefinierte Konverterfabrik zu definieren, und dieser Fehler auftritt, kann dies auch daran liegen, dass mehrere Variablen in einer Klasse mit einem falsch geschriebenen oder demselben serialisierten Namen vorhanden sind. IE:

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

Wenn Sie serialisierte Namen zweimal definiert haben (wahrscheinlich aus Versehen), wird genau dieser Fehler ausgelöst.

Update : Beachten Sie, dass diese Logik auch über die Vererbung gilt. Wenn Sie eine übergeordnete Klasse mit einem Objekt erweitern, das denselben serialisierten Namen wie in der Unterklasse hat, verursacht dies dasselbe Problem.


2
Dies war das Problem für mich, ich habe vergessen, ein Feld innerhalb einer untergeordneten Klasse zu entfernen, das ich in die übergeordnete Klasse verschoben habe. Danke, Mann!
Vucko

1
Danke, du hast mich vor 2 Tagen voller Kämpfe gerettet. Ich habe den gleichen Fehler gemacht, indem ich 2 Variablen mit denselben serialisierten Namen deklariert habe.
Valynk

9

Basierend auf dem Top-Kommentar habe ich meine Importe aktualisiert

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

Ich habe http://www.jsonschema2pojo.org/ verwendet, um Pojos aus Spotify-JSON-Ergebnissen zu erstellen und sicherzustellen, dass das Gson-Format angegeben wird.

Heutzutage gibt es Android Studio-Plugins, mit denen Sie die Pojo- oder Kotlin-Datenmodelle für Sie erstellen können. Eine großartige Option für Mac ist Quicktype. https://itunes.apple.com/us/app/paste-json-as-code-quicktype/id1330801220


4

In meinem Fall hatte ich ein TextView-Objekt in meiner Modalklasse und GSON wusste nicht, wie man es serialisiert. Das Markieren als "vorübergehend" löste das Problem.


Dies macht es zwar sichtbar, aber denken Sie daran, dass es nicht funktioniert, wenn Sie den Code (IE, durch Proguard) verschleiern und veröffentlichen. Es ist besser, stattdessen entweder die Anmerkungen SerializedName oder Exposed zu haben
PGMacDesign

4

Stellen Sie einfach sicher, dass Sie nicht zweimal denselben Serialisierungsnamen verwenden

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

entferne einfach einen von ihnen


Danke, du hast meinen Tag gerettet :)
Hemendra Gangwar

3

@ Silmarilos 'Beitrag hat mir geholfen, dieses Problem zu lösen. In meinem Fall habe ich "id" als serialisierten Namen verwendet, wie folgt:

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

und ich habe es geändert in

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

Alle arbeiten jetzt. Ich habe vergessen, dass 'id' ein Standardattribut ist.


1

Dies kann jemandem helfen

In meinem Fall habe ich fälschlicherweise SerializedName so geschrieben

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

Es sollte sein

@SerializedName("name")
String name;

@SerializedName("time")
String time;

0

Hey, ich habe heute das gleiche Problem durchgemacht. Ich habe einen ganzen Tag gebraucht, um eine Lösung zu finden, aber dies ist die Lösung, die ich endlich gefunden habe. Ich verwende Dagger in meinem Code und musste den Gson-Konverter in meiner Nachrüstinstanz implementieren.

Das war also vorher mein Code

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

Das war es, womit ich endete

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

Beachten Sie, dass es im ersten Beispiel keinen Konverter gibt. Wenn Sie Gson nicht instanziiert haben, fügen Sie ihn wie folgt hinzu

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

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

und stellen Sie sicher, dass Sie es in den Methodenaufruf zur Nachrüstung aufgenommen haben.

Ich hoffe noch einmal, dass dies jemandem wie mir hilft.


0

In meinem Fall war dies darauf zurückzuführen, dass versucht wurde, eine von meinem Dienst zurückgegebene Liste in eine ArrayList aufzunehmen. Also was ich hatte war:

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

wenn ich hätte haben sollen

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

Hoffe das hilft jemandem!


0

In meinem Fall bestand das Problem darin, dass in meinem SUPERCLASS-Modell dieses Feld definiert war. Sehr dumm, ich weiß ....

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.