Não foi possível criar o conversor para minha classe na biblioteca de Retrofit do Android

130

Estou migrando do Volley para o Retrofit, já tenho a classe gson que usei antes para converter a resposta JSONObject em um objeto que implementa as anotações do gson. Quando estou tentando fazer uma solicitação de obtenção de http usando a atualização, o meu aplicativo trava com este erro:

 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

Estou seguindo o guia no site de modernização e eu venho com essas implementações:

Esta é a minha atividade em que estou tentando executar a solicitação 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();
        }

    }
}

Minha interface que virou minha API

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

E, finalmente, a classe Pet, que deve ser a resposta:

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
fonte
por favor, adicione a cadeia de resposta desta ligação mysample.com/development/cuteness
koutuk
@koutuk isso é apenas uma amostra, btw eu mudei meu post já
Earwin Delos Santos
na qual linha você está recebendo erro ....
koutuk
você deve passar por youtube.com/watch?v=gGuUBlzmtPQ este vídeo
koutuk
ohh, esse é o antigo. Tente visitar retrofit square.github.io/retrofit
Earwin delos Santos

Respostas:

217

Antes 2.0.0, o conversor padrão era um conversor gson, mas, 2.0.0posteriormente, o conversor padrão é ResponseBody. Dos documentos:

Por padrão, o Retrofit só pode desserializar corpos HTTP para o ResponseBodytipo OkHttp e só pode aceitar seu RequestBodytipo para @Body.

Em 2.0.0+, você precisa especificar explicitamente que deseja um conversor Gson:

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

Você também precisará adicionar a seguinte dependência ao seu arquivo de classificação:

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

Use a mesma versão para o conversor e para o seu retrofit. O acima corresponde a essa dependência de atualização:

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

Além disso, observe que, ao escrever isso, os documentos de atualização não são completamente atualizados, e é por isso que esse exemplo causou problemas. Dos documentos:

Nota: Este site ainda está em processo de expansão para as novas APIs 2.0.

iagreen
fonte
Eu ainda estou tendo o problema #
34345052
216

Se alguém se deparar com isso no futuro porque você está tentando definir sua própria fábrica de conversores personalizados e está recebendo esse erro, também pode ser causado por ter várias variáveis ​​em uma classe com um erro de ortografia ou o mesmo nome serializado. IE:

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

Ter nomes serializados definidos duas vezes (provavelmente por engano) também gera esse mesmo erro.

Atualização : lembre-se de que essa lógica também é verdadeira por herança. Se você estender para uma classe pai com um objeto que tenha o mesmo nome serializado que você faz na subclasse, isso causará o mesmo problema.

PGMacDesign
fonte
2
Este foi o problema para mim, esqueci de remover um campo dentro de uma classe filho que eu mudei para a classe pai. Valeu cara!
Vucko
1
Obrigado, você me salvou de 2 dias de lutas. Cometi o mesmo erro declarando 2 variáveis ​​com os mesmos nomes serializados.
Valynk
9

Com base nos comentários principais, atualizei minhas importações

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

Eu usei o http://www.jsonschema2pojo.org/ para criar pojo's a partir dos resultados do Spotify json e certificar-se de especificar o formato Gson.

Atualmente, existem plugins do Android Studio que podem criar os modelos de dados do pojo ou Kotlin para você. Uma ótima opção para mac é o Quicktype. https://itunes.apple.com/us/app/paste-json-as-code-quicktype/id1330801220

Juan Mendez
fonte
5

apenas verifique se você não está usando o mesmo nome de serialização duas vezes

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

basta remover um deles

Mohamed Farahat
fonte
Obrigado, você salvou meu dia :)
Hemendra Gangwar
4

No meu caso, eu tinha um objeto TextView dentro da minha classe modal e o GSON não sabia como serializá-lo. Marcá-lo como 'transitório' resolveu o problema.

Saksham Dhawan
fonte
Embora isso o torne visível, lembre-se de que não funcionará se você ofuscar o código (IE, por meio de proguard) e publicá-lo; melhor ter tanto o SerializedName ou anotações exposta, em vez
PGMacDesign
3

A publicação de @ Silmarilos me ajudou a resolver isso. No meu caso, usei "id" como um nome serializado, assim:

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

e eu mudei para

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

Todos trabalhando agora. Esqueci que 'id' é um atributo padrão.

Glenncito
fonte
1

Isso pode ajudar alguém

No meu caso, por engano, escrevi SerializedName assim

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

Deveria ser

@SerializedName("name")
String name;

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

Ei, eu estava passando pelo mesmo problema hoje, levei um dia inteiro para encontrar uma solução, mas esta é a solução que encontrei finalmente. Estou usando o Dagger no meu código e eu precisava implementar o conversor Gson na minha instância de atualização.

então esse era meu 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();
    }

foi isso que eu acabei com

@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 como não há conversor no primeiro exemplo e, se você não instanciar o Gson, você o adiciona assim

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

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

e verifique se você o incluiu na chamada de método para atualização.

mais uma vez espero que isso ajude alguém como eu.

esquilo
fonte
0

No meu caso, foi devido a uma tentativa de levar uma lista retornada pelo meu serviço para um ArrayList. Então, o que eu tinha era:

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

quando eu deveria ter tido

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

Espero que isso ajude alguém!

Riot Goes Woof
fonte
0

No meu caso, o problema era que meu modelo SUPERCLASS tinha esse campo definido. Muito idiota, eu sei ....

SkyNet801
fonte