529 Stimmen

Deserialisieren eines List<T>-Objekts mit Gson?

Ich möchte ein Listenobjekt über Google Gson übertragen, aber ich weiß nicht, wie man generische Typen deserialisiert.

Was ich versucht habe, nachdem ich mir este (die Antwort von BalusC):

MyClass mc = new Gson().fromJson(result, new List<MyClass>() {}.getClass());

aber dann bekomme ich in Eclipse die Fehlermeldung "The type new List<MyClass>() {} muss die geerbte abstrakte Methode implementieren..." und wenn ich eine schnelle Lösung verwende, erhalte ich ein Monster von über 20 Methoden-Stubs.

Ich bin mir ziemlich sicher, dass es eine einfachere Lösung gibt, aber ich scheine sie nicht zu finden!

Jetzt habe ich das hier:

Type listType = new TypeToken<List<MyClass>>() {}.getType();

MyClass mc = new Gson().fromJson(result, listType);

Ich erhalte jedoch die folgende Ausnahme bei der fromJson Linie:

java.lang.NullPointerException
at org.apache.harmony.luni.lang.reflect.ListOfTypes.length(ListOfTypes.java:47)
at org.apache.harmony.luni.lang.reflect.ImplForType.toString(ImplForType.java:83)
at java.lang.StringBuilder.append(StringBuilder.java:203)
at com.google.gson.JsonDeserializerExceptionWrapper.deserialize(JsonDeserializerExceptionWrapper.java:56)
at com.google.gson.JsonDeserializationVisitor.invokeCustomDeserializer(JsonDeserializationVisitor.java:88)
at com.google.gson.JsonDeserializationVisitor.visitUsingCustomHandler(JsonDeserializationVisitor.java:76)
at com.google.gson.ObjectNavigator.accept(ObjectNavigator.java:106)
at com.google.gson.JsonDeserializationContextDefault.fromJsonArray(JsonDeserializationContextDefault.java:64)
at com.google.gson.JsonDeserializationContextDefault.deserialize(JsonDeserializationContextDefault.java:49)
at com.google.gson.Gson.fromJson(Gson.java:568)
at com.google.gson.Gson.fromJson(Gson.java:515)
at com.google.gson.Gson.fromJson(Gson.java:484)
at com.google.gson.Gson.fromJson(Gson.java:434)

I hacer fangen JsonParseExceptions y result ist nicht null.

Ich überprüfte listType mit dem Debugger und erhielt folgendes Ergebnis:

  • list Type
    • args = ListOfTypes
      • list = null
      • resolvedTypes = Type[ 1 ]
    • loader = PathClassLoader
    • ownerType0 = null
    • ownerTypeRes = null
    • rawType = Class (java.util.ArrayList)
    • rawTypeName = "java.util.ArrayList"

Es scheint also, dass die getClass Aufrufen nicht richtig funktioniert hat. Irgendwelche Vorschläge...?

Ich habe die Gson Benutzerhandbuch . Es erwähnt eine Laufzeit-Ausnahme, die während des Parsens eines generischen Typs zu Json passieren sollte. Ich tat es "falsch" (nicht oben gezeigt), genau wie im Beispiel, aber nicht erhalten, dass Ausnahme überhaupt. Also änderte ich die Serialisierung wie im Benutzerhandbuch vorgeschlagen. Das hat aber nicht geholfen.

Editar:

Gelöst, siehe meine Antwort unten.

1100voto

uncaught_exceptions Punkte 20960

Methode zur Deserialisierung einer generischen Sammlung:

import java.lang.reflect.Type;
import com.google.gson.reflect.TypeToken;

...

Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> yourClassList = new Gson().fromJson(jsonArray, listType);

Da mehrere Personen in den Kommentaren darauf hingewiesen haben, hier eine Erklärung, wie die TypeToken Klasse verwendet wird. Die Konstruktion new TypeToken<...>() {}.getType() erfasst einen Kompilierzeittyp (zwischen dem < y > ) in eine Laufzeit java.lang.reflect.Type Objekt. Anders als ein Class Objekt, das nur einen rohen (gelöschten) Typ repräsentieren kann, die Type Objekt kann jeden Typ in der Java-Sprache darstellen, einschließlich einer parametrisierten Instanziierung eines generischen Typs.

El TypeToken Klasse selbst hat keinen öffentlichen Konstruktor, weil man sie nicht direkt konstruieren soll. Stattdessen konstruieren Sie immer eine anonyme Unterklasse (daher das {} die ein notwendiger Bestandteil dieses Ausdrucks ist).

Durch das Löschen des Typs wird die TypeToken Klasse kann nur Typen erfassen, die zur Kompilierzeit vollständig bekannt sind. (Das heißt, Sie können nicht new TypeToken<List<T>>() {}.getType() für einen Typ-Parameter T .)

Weitere Informationen finden Sie in der Dokumentation für die TypeToken Klasse .

308voto

DevNG Punkte 5705

Eine andere Möglichkeit ist die Verwendung eines Arrays als Typ, z. B.:

MyClass[] mcArray = gson.fromJson(jsonString, MyClass[].class);

Auf diese Weise vermeiden Sie den ganzen Ärger mit dem Type-Objekt, und wenn Sie wirklich eine Liste benötigen, können Sie das Array jederzeit in eine Liste umwandeln:

List<MyClass> mcList = Arrays.asList(mcArray);

IMHO ist dies viel besser lesbar.

Und damit es eine tatsächliche Liste ist (die geändert werden kann, siehe Einschränkungen von Arrays.asList() ), dann gehen Sie wie folgt vor:

List<MyClass> mcList = new ArrayList<>(Arrays.asList(mcArray));

86voto

Linh Punkte 49889

Seit Gson 2.8, können wir util Funktion wie diese erstellen:

public <T> List<T> getList(String jsonArray, Class<T> clazz) {
    Type typeOfT = TypeToken.getParameterized(List.class, clazz).getType();
    return new Gson().fromJson(jsonArray, typeOfT);
}

Beispiel für die Verwendung:

String jsonArray = ...
List<User> user = getList(jsonArray, User.class);

32voto

Happier Punkte 808

Siehe dazu diesen Beitrag. Java Type Generic als Argument für GSON

Ich habe eine bessere Lösung für dieses Problem. Hier ist die Wrapper-Klasse für Liste, so dass der Wrapper den genauen Typ der Liste speichern kann.

public class ListOfJson<T> implements ParameterizedType
{
  private Class<?> wrapped;

  public ListOfJson(Class<T> wrapper)
  {
    this.wrapped = wrapper;
  }

  @Override
  public Type[] getActualTypeArguments()
  {
      return new Type[] { wrapped };
  }

  @Override
  public Type getRawType()
  {
    return List.class;
  }

  @Override
  public Type getOwnerType()
  {
    return null;
  }
}

Und dann kann der Code einfach sein:

public static <T> List<T> toList(String json, Class<T> typeClass)
{
    return sGson.fromJson(json, new ListOfJson<T>(typeClass));
}

28voto

Roc Boronat Punkte 10450

Wep, eine andere Möglichkeit, das gleiche Ergebnis zu erzielen. Wir verwenden es wegen seiner Lesbarkeit.

Anstatt diesen schwer zu lesenden Satz zu schreiben:

Type listType = new TypeToken<ArrayList<YourClass>>(){}.getType();
List<YourClass> list = new Gson().fromJson(jsonArray, listType);

Erstellen Sie eine leere Klasse, die eine Liste Ihres Objekts erweitert:

public class YourClassList extends ArrayList<YourClass> {}

Und verwenden Sie es beim Parsen des JSON:

List<YourClass> list = new Gson().fromJson(jsonArray, YourClassList.class);

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X