method - java generics wildcard




Google Gson-Deserialisierung Liste<Klasse> Objekt?(generischer Typ) (8)

Ich möchte ein Listenobjekt über Google Gson übertragen, kann aber keine generischen Typen deserialisieren.

Was ich versuchte, nachdem ich mir this (BalusCs Antwort):

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

aber dann bekomme ich einen Fehler in Eclipse und sage "Der Typ new List () {} muss die vererbte abstrakte Methode implementieren ..." und wenn ich eine schnelle Lösung verwende, bekomme ich ein Monster von über 20 Methoden-Stubs.

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

Bearbeiten:

Jetzt habe ich

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

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

Allerdings bekomme ich die folgende Ausnahme in 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)

Ich fange JsonParseExceptions und "Ergebnis" ist nicht null.

Ich habe listType mit dem Debugger überprüft und folgendes bekommen:

  • Liste Typ
    • args = ListOfTypes
      • Liste = null
      • aufgelösteTypen = Typ [1]
    • loader = PfadClassLoader
    • ownerType0 = null
    • ownerTypeRes = null
    • rawType = Klasse (java.util.ArrayList)
    • rawTypeName = "java.util.ArrayList"

Es scheint also, dass die "getClass" -Aufruf nicht richtig funktioniert. Irgendwelche Vorschläge...?

Edit2: Ich habe das Gson User Guide überprüft. Es erwähnt eine Laufzeitausnahme, die beim Analysieren eines generischen Typs nach Json passieren sollte. Ich habe es "falsch" gemacht (nicht oben gezeigt), genau wie im Beispiel, aber habe diese Ausnahme überhaupt nicht bekommen. Also habe ich die Serialisierung wie im Benutzerhandbuch vorgeschlagen geändert. Hat aber nicht geholfen.

Edit3: Gelöst, siehe meine Antwort unten.


Da es meine ursprüngliche Frage beantwortet, habe ich die Antwort von doc_180 akzeptiert, aber wenn jemand erneut auf dieses Problem stößt, werde ich auch die zweite Hälfte meiner Frage beantworten:

Der von mir beschriebene NullPointerError hatte nichts mit der Liste selbst zu tun, sondern mit ihrem Inhalt!

Die "MyClass" -Klasse hatte keinen "no args" -Konstruktor, und keiner hatte seine Oberklasse. Nachdem ich MyClass und seine Oberklasse einen einfachen "MyClass ()" -Konstruktor hinzugefügt hatte, funktionierte alles einwandfrei, einschließlich der Listen-Serialisierung und -Deserialisierung, wie von doc_180 vorgeschlagen.


Eine andere Möglichkeit besteht darin, ein Array als Typ zu verwenden, z.

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

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

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

IMHO ist das viel besser lesbar.

Und um es zu einer tatsächlichen Liste zu machen (die geändert werden kann, siehe Einschränkungen von Arrays.asList() ), dann mache einfach folgendes:

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

Hier ist eine Lösung, die mit einem dynamisch definierten Typ arbeitet. Der Trick besteht darin, den richtigen Array-Typ mit Array.newInstance () zu erstellen.

    public static <T> List<T> fromJsonList(String json, Class<T> clazz) {
    Object [] array = (Object[])java.lang.reflect.Array.newInstance(clazz, 0);
    array = gson.fromJson(json, array.getClass());
    List<T> list = new ArrayList<T>();
    for (int i=0 ; i<array.length ; i++)
        list.add(clazz.cast(array[i]));
    return list; 
}

Ich möchte für eine weitere Möglichkeit hinzufügen. Wenn Sie TypeToken nicht verwenden und das Array json objects in eine ArrayList konvertieren möchten, können Sie folgendermaßen vorgehen:

Wenn Ihre JSON-Struktur wie folgt aussieht:

{

"results": [
    {
        "a": 100,
        "b": "value1",
        "c": true
    },
    {
        "a": 200,
        "b": "value2",
        "c": false
    },
    {
        "a": 300,
        "b": "value3",
        "c": true
    }
]

}

und deine Klassenstruktur ist wie folgt:

public class ClassName implements Parcelable {

    public ArrayList<InnerClassName> results = new ArrayList<InnerClassName>();
    public static class InnerClassName {
        int a;
        String b;
        boolean c;      
    }
}

dann kannst du es analysieren wie:

Gson gson = new Gson();
final ClassName className = gson.fromJson(data, ClassName.class);
int currentTotal = className.results.size();

Jetzt können Sie auf jedes Element des className-Objekts zugreifen.


In meinem Fall @ uncaught_exceptions die Antwort hat nicht funktioniert, ich musste List.class anstelle von java.lang.reflect.Type :

String jsonDuplicatedItems = request.getSession().getAttribute("jsonDuplicatedItems").toString();
List<Map.Entry<Product, Integer>> entries = gson.fromJson(jsonDuplicatedItems, List.class);

Methode zum Deserialisieren der 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 dies erwähnt haben, TypeToken hier eine Erläuterung, wie die TypeToken Klasse verwendet wird. Die Konstruktion new TypeToken<...>() {}.getType() erfasst einen Kompilierzeittyp (zwischen < und > ) in ein Laufzeitobjekt java.lang.reflect.Type . Im Gegensatz zu einem Klassenobjekt, das nur einen rohen (gelöschten) Typ darstellen kann, kann das Type Objekt einen beliebigen Typ in der Java-Sprache darstellen, einschließlich einer parametrisierten Instanziierung eines generischen Typs.

Die TypeToken Klasse selbst hat keinen öffentlichen Konstruktor, da Sie sie nicht direkt TypeToken sollen. Stattdessen konstruieren Sie immer eine anonyme Unterklasse (daher das {} , das ein notwendiger Teil dieses Ausdrucks ist).

Aufgrund der TypeToken kann die TypeToken Klasse nur Typen erfassen, die zur Kompilierungszeit vollständig bekannt sind. (Das heißt, Sie können new TypeToken<List<T>>() {}.getType() für einen Typparameter T nicht new TypeToken<List<T>>() {}.getType() .)

Weitere Informationen finden Sie in der Dokumentation zur TypeToken Klasse .


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

Ich habe dafür eine bessere Lösung. Hier ist die Wrapper-Klasse für die Liste, sodass der Wrapper den genauen Listentyp 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));
}

Wep, ein anderer Weg, um das gleiche Ergebnis zu erzielen. Wir verwenden es für seine Lesbarkeit.

Anstatt diesen schwer zu lesenden Satz zu machen:

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 benutze es beim Parsen des JSON:

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






gson