J'ai quelques problèmes avec l'implémentation de Json Deserialization dans mon application Android (avec la bibliothèque Gson)
J'ai fait classe comme ça
public class MyJson<T>{
public List<T> posts;
}
Et l'appel de désérialisation est:
public class JsonDownloader<T> extends AsyncTask<Void, Void, MyJson<T>> {
...
protected MyJson<T> doInBackground(Void... params) {
...
Reader reader = new InputStreamReader(content);
GsonBuilder gson = new GsonBuilder();
Type collectionType = new TypeToken<MyJson<T>>() {}.getType();
result = gson.create().fromJson(reader, collectionType);
...
}
}
Le problème est que la liste result.posts après appel contient un tableau d'objets LinkedTreeMap (avec les valeurs correctes, donc le problème est Désérialisation) au lieu d'objets MyJson. Lorsque j'utilise MyObject au lieu de T, tout fonctionne correctement et MyObject est correct.
Alors, est-il possible d'implémenter un appel de désérialisation sans créer de désérialiseur personnalisé?
Vous devez spécifier le type de T
au moment de la désérialisation. Comment votre List
de posts
serait-elle créée si Gson
ne savait pas quelle Type
instancier? Il ne peut pas rester T
pour toujours. Ainsi, vous fourniriez le type T
en tant que paramètre Class
.
En supposant maintenant que le type de posts
soit String
, vous désérialiseriez MyJson<String>
de la manière suivante (j'ai également ajouté un paramètre String json
pour plus de simplicité; vous liriez votre reader
comme auparavant):
doInBackground(String.class, "{posts: [\"article 1\", \"article 2\"]}");
protected MyJson<T> doInBackground(Class<T> type, String json, Void... params) {
GsonBuilder gson = new GsonBuilder();
Type collectionType = new TypeToken<MyJson<T>>(){}.getType();
MyJson<T> myJson = gson.create().fromJson(json, collectionType);
System.out.println(myJson.getPosts()); // ["article 1", "article 2"]
return myJson;
}
De même, pour désérialiser une MyJson
de Boolean
objets
doInBackground(Boolean.class, "{posts: [true, false]}");
protected MyJson<T> doInBackground(Class<T> type, String json, Void... params) {
GsonBuilder gson = new GsonBuilder();
Type collectionType = new TypeToken<MyJson<T>>(){}.getType();
MyJson<T> myJson = gson.create().fromJson(json, collectionType);
System.out.println(myJson.getPosts()); // [true, false]
return myJson;
}
J'ai supposé que MyJson<T>
était le même pour mes exemples
public class MyJson<T> {
public List<T> posts;
public List<T> getPosts() {
return posts;
}
}
Donc, si vous vouliez désérialiser un List<MyObject>
, vous invoqueriez la méthode comme suit:
// assuming no Void parameters were required
MyJson<MyObject> myJson = doInBackground(MyObject.class);
As-tu essayé?
gson.create().fromJson(reader, MyJson.class);
MODIFIER
Après avoir lu this post, il semble que vous utilisiez Type
comme correct. Je crois que votre problème est l'utilisation de T
. N'oubliez pas qu'avec Java, il y a effacement de type. Cela signifie qu'au moment de l'exécution, toutes les instances de T
sont remplacées par Object
. Par conséquent, au moment de l'exécution, ce que vous passez GSON est vraiment MyJson<Object>
. Si vous essayez cela avec une classe concrète à la place de <T>
, je crois que cela fonctionnerait.
Google Gson - désérialiser un objet de la liste <class>? (type générique)
Donc, la réponse ci-dessus n'a pas fonctionné pour moi, après essais et erreurs, voici comment mon code s'est terminé:
public class AbstractListResponse<T> {
private List<T> result;
public List<T> getResult() {
return this.result;
}
}
La partie importante ici est la signature de la méthode, y compris le '<T>' à gauche.
protected <T> AbstractListResponse<T> parseAbstractResponse(String json, TypeToken type) {
return new GsonBuilder()
.create()
.fromJson(json, type.getType());
}
Lors de l'appel de Gson, la méthode reçoit le TypeToken de l'objet générique.
TypeToken<AbstractListResponse<MyDTO>> typeToken = new TypeToken<AbstractListResponse<MyDTO>>() {};
AbstractListResponse<MyDTO> responseBase = parseAbstractResponse(json, typeToken);
Et enfin, le TypeToken peut utiliser MyDTO, ou même un simple objet, uniquement MyDTO.
Pour ceux qui luttent avec Kotlin comme moi, j'ai trouvé cette façon de travailler
val type = object : TypeToken<MyJson<MyObject>>() { }.type
val response = gson.fromJson<MyJson<MyObject>>(reader, type)
Notez que l'appel d'une fonction générique nécessite les arguments de type sur le site d'appel après le nom de la fonction (vu ici )