No se puede crear un convertidor para mi clase en la biblioteca de Android Retrofit

130

Estoy migrando de usar Volley a Retrofit, ya tengo la clase gson que usé antes para convertir la respuesta JSONObject en un objeto que implementa anotaciones gson. Cuando estoy tratando de hacer una solicitud de obtención de http usando la actualización, pero mi aplicación se bloquea con este error:

 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

Im siguiendo la guía de adaptación sitio y subir con estas implementaciones:

Esta es mi actividad en la que intento ejecutar la solicitud 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();
        }

    }
}

Mi interfaz que resultó ser mi API

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

Y finalmente la clase Pet, que debería ser la respuesta:

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];
        }
    };
}
Earwin delos Santos
fuente
agregue la cadena de respuesta de este enlace mysample.com/development/cuteness
koutuk
@koutuk eso es solo una muestra, por cierto, ya cambié mi publicación
Earwin delos Santos
en qué línea está obteniendo error ...
koutuk
deberías
visitar
ohh ese es el viejo intenta visitar retrofit square.github.io/retrofit
Earwin delos Santos

Respuestas:

217

Antes de 2.0.0, el convertidor predeterminado era un convertidor gson, pero en 2.0.0y luego el convertidor predeterminado es ResponseBody. De los documentos:

Por defecto, Retrofit solo puede deserializar cuerpos HTTP en el ResponseBodytipo de OkHttp y solo puede aceptar su RequestBodytipo @Body.

En 2.0.0+, debe especificar explícitamente que desea un convertidor Gson:

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

También deberá agregar la siguiente dependencia a su archivo gradle:

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

Use la misma versión para el convertidor que para su modificación. Lo anterior coincide con esta dependencia de modificación:

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

Además, tenga en cuenta que al escribir esto, los documentos de actualización no están completamente actualizados, por lo que ese ejemplo lo metió en problemas. De los documentos:

Nota: Este sitio todavía está en proceso de expansión para las nuevas API 2.0.

iagreen
fuente
sigo teniendo el problema
user3475052
217

Si alguien se encuentra con esto en el futuro porque está tratando de definir su propia fábrica de convertidores personalizados y está recibiendo este error, también puede ser causado por tener múltiples variables en una clase con un nombre mal escrito o el mismo nombre serializado. ES DECIR:

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

Tener nombres serializados definidos dos veces (probablemente por error) también arrojará exactamente el mismo error.

Actualización : tenga en cuenta que esta lógica también es válida a través de la herencia. Si se extiende a una clase primaria con un objeto que tiene el mismo nombre serializado que en la subclase, causará este mismo problema.

PGMacDesign
fuente
2
Este fue el problema para mí, olvidé eliminar un campo dentro de una clase secundaria que moví a la clase principal. ¡Gracias hombre!
Vucko
1
Gracias, me salvaste de 2 días de luchas. Cometí el mismo error al declarar 2 variables con los mismos nombres serializados.
Valynk
9

Basado en el comentario principal, actualicé mis importaciones

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

Utilicé http://www.jsonschema2pojo.org/ para crear pojo's a partir de los resultados de Spotify json y me aseguré de especificar el formato Gson.

En estos días hay complementos de Android Studio que pueden crear los modelos de datos de pojo o Kotlin por usted. Una gran opción para mac es Quicktype. https://itunes.apple.com/us/app/paste-json-as-code-quicktype/id1330801220

Juan mendez
fuente
5

solo asegúrese de no estar utilizando el mismo nombre de serialización dos veces

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

solo quita uno de ellos

Mohamed Farahat
fuente
Gracias, me salvaste el día :)
Hemendra Gangwar
4

En mi caso, tenía un objeto TextView dentro de mi clase modal y GSON no sabía cómo serializarlo. Marcarlo como 'transitorio' resolvió el problema.

Saksham Dhawan
fuente
Si bien esto lo hará visible, tenga en cuenta que no funcionará si ofusca el código (IE, a través de Proguard) y lo publica; mejor tener las anotaciones SerializedName o Exposed en su lugar
PGMacDesign
3

La publicación de @ Silmarilos me ayudó a resolver esto. En mi caso, fue que usé "id" como un nombre serializado, como este:

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

y lo cambié a

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

Todos trabajando ahora. Olvidé que 'id' es un atributo predeterminado.

Glenncito
fuente
1

Esto puede ayudar a alguien

En mi caso, por error, escribí SerializedName como este

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

Debería ser

@SerializedName("name")
String name;

@SerializedName("time")
String time;
RAJESH KUMAR ARUMUGAM
fuente
0

Hola, estaba pasando por el mismo problema hoy me llevó un día entero encontrar una solución, pero esta es la solución que encontré finalmente. Estoy usando Dagger en mi código y necesitaba implementar el convertidor Gson en mi instancia de actualización.

entonces este era mi código antes

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

esto fue con lo que terminé

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

observe cómo no hay convertidor en el primer ejemplo y la adición si no ha instanciado Gson, lo agrega así

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

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

y asegúrese de haberlo incluido en la llamada al método de modificación.

Una vez más espero que esto ayude a alguien como yo.

ardilla
fuente
0

En mi caso, se debió a que mi servicio devolvió una Lista a una ArrayList. Entonces lo que tuve fue:

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

cuando debería haber tenido

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

¡Espero que esto ayude a alguien!

Riot Goof Woof
fuente
0

En mi caso, el problema era que mi modelo SUPERCLASS tenía este campo definido en él. Muy estúpido, lo sé ...

SkyNet801
fuente