En migrant de Volley à Retrofit, j’ai déjà utilisé la classe gson que j’avais utilisée auparavant pour convertir la réponse JSONObject en un objet implémentant des annotations gson. Lorsque j'essaie de créer une requête HTTP avec retrofit, mon application se bloque alors avec l'erreur suivante:
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
Je suis le guide dans retrofit site et je propose ces implémentations:
Voici mon activité pour laquelle j'essaie d'exécuter la requête http rétro:
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();
}
}
}
Mon interface qui s'est avérée être mon API
public interface GitHubService {
@GET("/ **sample here** /{petId}/{otherPet}")
Call<Pet> getResponse(@Path("petId") String userId, @Path("otherPet") String otherPet);
}
Et enfin la classe Pet qui devrait être la réponse:
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];
}
};
}
Avant 2.0.0
, le convertisseur par défaut était un convertisseur gson, mais dans 2.0.0
et plus tard, le convertisseur par défaut est ResponseBody
. De la docs:
Par défaut, Retrofit peut uniquement désérialiser les corps HTTP dans le type
ResponseBody
d'OkHttp et n'accepter que son typeRequestBody
pour@Body
.
Dans 2.0.0+
, vous devez spécifier explicitement que vous voulez un convertisseur Gson:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl("**sample base url here**")
.addConverterFactory(GsonConverterFactory.create())
.build();
Vous devrez également ajouter la dépendance suivante à votre fichier gradle:
compile 'com.squareup.retrofit2:converter-gson:2.1.0'
Utilisez la même version pour le convertisseur que pour votre adaptation. Ce qui précède correspond à cette dépendance de modernisation:
compile ('com.squareup.retrofit2:retrofit:2.1.0')
De plus, notez qu'au moment de l'écriture, les documents de mise à niveau ne sont pas complètement mis à jour, c'est pourquoi cet exemple vous a posé problème. De la docs:
Remarque: Ce site est toujours en cours d’extension pour les nouvelles API 2.0.
Si jamais quelqu'un rencontre cela à l'avenir parce que vous tentez de définir votre propre fabrique de convertisseurs personnalisée et obtenez cette erreur, cela peut également être causé par le fait que plusieurs variables d'une classe portent le même nom sérialisé. C'EST À DIRE:
public class foo {
@SerializedName("name")
String firstName;
@SerializedName("name")
String lastName;
}
Ayant des noms sérialisés définis deux fois (probablement par erreur), cette même erreur sera également renvoyée.
Mise à jour: Gardez à l'esprit que cette logique est également vraie via l'héritage. Si vous étendez à une classe parente avec un objet qui porte le même nom sérialisé que celui de la sous-classe, le même problème se produira.
Sur la base des meilleurs commentaires, j'ai mis à jour mes importations
implementation 'com.squareup.retrofit2:retrofit:2.1.0'
implementation 'com.squareup.retrofit2:converter-gson:2.1.0'
J'ai utilisé http://www.jsonschema2pojo.org/ afin de créer des pojos à partir des résultats Spotify json et en veillant à spécifier le format Gson.
De nos jours, Android Studio plugins permettent de créer pour vous les modèles de données pojo ou Kotlin. Quicktype est une excellente option pour mac. https://iTunes.Apple.com/us/app/paste-json-as-code-quicktype/id133080122
Dans mon cas, j'avais un objet TextView dans ma classe modale et GSON ne savait pas comment le sérialiser. Le marquer comme "transitoire" a résolu le problème.
Le message de @ Silmarilos m'a aidé à résoudre ce problème. Dans mon cas, c’est que j’ai utilisé "id" comme nom sérialisé, comme ceci:
@SerializedName("id")
var node_id: String? = null
et je l'ai changé pour
@SerializedName("node_id")
var node_id: String? = null
Tous travaillent maintenant. J'ai oublié que "id" est un attribut par défaut.
Cela peut aider quelqu'un
Dans mon cas, j'ai écrit à tort SerializedName comme ceci
@SerializedName("name","time")
String name,time;
CA devrait etre
@SerializedName("name")
String name;
@SerializedName("time")
String time;
Dans mon cas, il s’agissait d’essayer de prendre une liste renvoyée par mon service dans une liste de tableaux. Donc ce que j'avais était:
@Json(name = "items")
private ArrayList<ItemModel> items;
quand j'aurais dû avoir
@Json(name = "items")
private List<ItemModel> items;
J'espère que ça aide quelqu'un!
Hé, je passais par le même problème aujourd'hui, il m'a fallu une journée entière pour trouver une solution, mais c'est la solution que j'ai finalement trouvée. J'utilise Dagger dans mon code et j'avais besoin d'implémenter le convertisseur Gson dans mon exemple de mise à niveau.
donc c'était mon code avant
@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();
}
c'est ce que j'ai fini avec
@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();
}
remarquez comme il n'y a pas de convertisseur dans le premier exemple et l'addition si vous n'avez pas instancié Gson vous l'ajoutez comme ceci
@Provides
@Singleton
Gson provideGson() {
GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES);
return gsonBuilder.create();
}
et assurez-vous que vous l'avez inclus dans l'appel de méthode pour la mise à niveau.
encore une fois, espérons que cela aidera quelqu'un comme moi.