Ich habe Probleme mit der Implementierung von Json Deserialization in meiner Android-Anwendung (mit der Gson-Bibliothek).
Ich habe Klasse so gemacht
public class MyJson<T>{
public List<T> posts;
}
Und Deserialisierungsaufruf lautet:
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);
...
}
}
Das Problem ist, dass result.posts list after call ein Array von LinkedTreeMap-Objekten (mit korrekten Werten, also Deserialisierung des Problems) anstelle von MyJson-Objekten enthält. Wenn ich MyObject anstelle von T verwende, läuft alles einwandfrei und MyObject ist korrekt.
Gibt es eine Möglichkeit, einen Deserialisierungsaufruf zu implementieren, ohne einen benutzerdefinierten Deserialisierer zu erstellen?
Sie müssen den Typ von T
zum Zeitpunkt der Deserialisierung angeben. Wie würde Ihr List
von posts
erstellt, wenn Gson
nicht wüsste, welches Type
zu instanziieren ist? Es kann nicht für immer T
bleiben. Sie würden also den Typ T
als Class
-Parameter angeben.
Angenommen, der Typ von posts
war String
, als den Sie MyJson<String>
Deserialisieren würden (der Einfachheit halber habe ich auch einen String json
- Parameter hinzugefügt; Sie würden aus lesen Ihr reader
wie zuvor):
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;
}
Ebenso zum Deserialisieren eines MyJson
von Boolean
Objekten
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;
}
Ich habe MyJson<T>
Für meine Beispiele als angenommen
public class MyJson<T> {
public List<T> posts;
public List<T> getPosts() {
return posts;
}
}
Wenn Sie also nach einer Deserialisierung von List<MyObject>
Suchen, rufen Sie die Methode als auf
// assuming no Void parameters were required
MyJson<MyObject> myJson = doInBackground(MyObject.class);
Hast du es versucht?
gson.create().fromJson(reader, MyJson.class);
EDIT
Nach dem Lesen von this post scheint die Verwendung von Type
richtig zu sein. Ich glaube, Ihr Problem ist die Verwendung von T
. Sie müssen sich daran erinnern, dass es bei Java eine Typlöschung gibt. Das bedeutet, dass zur Laufzeit alle Instanzen von T
durch Object
ersetzt werden. Zur Laufzeit ist also GSON wirklich MyJson<Object>
. Wenn Sie dies mit einer konkreten Klasse anstelle von <T>
versucht haben, glaube ich, dass es funktionieren würde.
Google Gson - Liste <Klasse> -Objekt deserialisieren? (generischer Typ)
Die obige Antwort funktionierte also nicht für mich. Nach dem Ausprobieren endete mein Code:
public class AbstractListResponse<T> {
private List<T> result;
public List<T> getResult() {
return this.result;
}
}
Der wichtige Teil hier ist die Methodensignatur, einschließlich des '<T>' auf der linken Seite.
protected <T> AbstractListResponse<T> parseAbstractResponse(String json, TypeToken type) {
return new GsonBuilder()
.create()
.fromJson(json, type.getType());
}
Beim Aufruf von Gson erhält die Methode das TypeToken des generischen Objekts.
TypeToken<AbstractListResponse<MyDTO>> typeToken = new TypeToken<AbstractListResponse<MyDTO>>() {};
AbstractListResponse<MyDTO> responseBase = parseAbstractResponse(json, typeToken);
Und schließlich kann das TypeToken MyDTO verwenden, oder sogar ein einfaches Objekt, nur MyDTO.
Für jeden, der wie ich mit Kotlin kämpft, habe ich diesen Weg gefunden
val type = object : TypeToken<MyJson<MyObject>>() { }.type
val response = gson.fromJson<MyJson<MyObject>>(reader, type)
Beachten Sie, dass beim Aufruf einer generischen Funktion die Typargumente an der Aufrufstelle nach dem Namen der Funktion erforderlich sind (gesehen hier ).