Chcę przenieść obiekt listy za pośrednictwem Google Gson, ale nie wiem, jak dokonać deserializacji typów ogólnych.
Co próbowałem po obejrzeniu tego (odpowiedź BalusC):
MyClass mc = new Gson().fromJson(result, new List<MyClass>(){}.getClass());
ale wtedy pojawia się błąd w zaćmieniu, mówiąc: „Typ new List () {} musi implementować odziedziczoną metodę abstrakcyjną ...” i jeśli użyję szybkiej poprawki, dostanę potwora ponad 20 kodów pośredniczących metody.
Jestem prawie pewien, że istnieje łatwiejsze rozwiązanie, ale wydaje się, że nie jestem w stanie go znaleźć!
Edytować:
Teraz mam
Type listType = new TypeToken<List<MyClass>>()
{
}.getType();
MyClass mc = new Gson().fromJson(result, listType);
Jednak w wierszu „fromJson” pojawia się następujący wyjątek:
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 zrobić JsonParseExceptions połowów i „wynik” nie jest null.
Sprawdziłem listType za pomocą debugera i otrzymałem następujące informacje:
- typ listy
- args = ListOfTypes
- list = null
- resolvedTypes = Typ [1]
- loader = PathClassLoader
- ownerType0 = null
- ownerTypeRes = null
- rawType = Klasa (java.util.ArrayList)
- rawTypeName = "java.util.ArrayList"
- args = ListOfTypes
więc wygląda na to, że wywołanie „getClass” nie działało poprawnie. Jakieś sugestie...?
Edycja2: Sprawdziłem w Podręczniku użytkownika Gson . Wspomina wyjątek czasu wykonywania, który powinien wystąpić podczas analizowania typu ogólnego dla Jsona. Zrobiłem to „źle” (nie pokazano powyżej), tak jak w przykładzie, ale w ogóle nie dostałem tego wyjątku. Zmieniłem więc serializację zgodnie z sugerowanym podręcznikiem użytkownika. Jednak nie pomogło.
Edycja3: Rozwiązane, patrz moja odpowiedź poniżej.
TokenType
. Próbowałeś w ten sposób?Odpowiedzi:
Metoda deserializacji ogólnej kolekcji:
Ponieważ kilka osób w komentarzach wspomniało o tym, oto wyjaśnienie, w jaki sposób
TypeToken
używana jest klasa. Konstrukcjanew TypeToken<...>() {}.getType()
przechwytuje typ czasu kompilacji (między<
i>
) dojava.lang.reflect.Type
obiektu wykonawczego . W przeciwieństwie doClass
obiektu, który może reprezentować tylko surowy (wymazany) typ,Type
obiekt może reprezentować dowolny typ w języku Java, w tym sparametryzowaną instancję typu ogólnego.Sama
TypeToken
klasa nie ma publicznego konstruktora, ponieważ nie należy jej konstruować bezpośrednio. Zamiast tego zawsze konstruujesz anonimową podklasę (stąd{}
, która jest niezbędną częścią tego wyrażenia).Z powodu wymazywania typu
TypeToken
klasa jest w stanie przechwytywać tylko te typy, które są w pełni znane w czasie kompilacji. (Oznacza to, że nie można tego zrobićnew TypeToken<List<T>>() {}.getType()
dla parametru typuT
).Aby uzyskać więcej informacji, zobacz dokumentację
TypeToken
klasy .źródło
{ "myObjectArray":[ {....} , {....} , {....} ] }
, stworzyłem plik modelu{....}
, w jaki sposób uzyskać ten ogólny kod kolekcji, aby nie zakładać, że mój element główny jest tablicą bez tworzenia nowego pliku zagnieżdżonegoInnym sposobem jest użycie tablicy jako typu, np .:
W ten sposób unikniesz kłopotów z obiektem Type, a jeśli naprawdę potrzebujesz listy, zawsze możesz przekonwertować tablicę na listę poprzez:
IMHO jest to o wiele bardziej czytelne.
Aby stała się rzeczywistą listą (którą można modyfikować, zobacz ograniczenia
Arrays.asList()
), wykonaj następujące czynności:źródło
MyClass
wartości, która zostanie zdefiniowana dynamicznie!T[] yourClassList = gson.fromJson(message, T[].class);
// nie można wybrać zmiennej typumcList
w tej odpowiedzi był tylko wynikiem połączenia zArrays.asList
. Ta metoda zwraca listę, na której większość, jeśli nie wszystkie metody opcjonalne, pozostają niezaimplementowane i wyrzuca wyjątki. Na przykład nie można dodać żadnego elementu do tej listy. Jak sugeruje późniejsza edycja,Arrays.asList
ma ograniczenia, a zawinięcie jej w rzeczywistąArrayList
pozwala uzyskać listę, która jest bardziej przydatna w wielu przypadkach.Array.newInstance(clazz, 0).getClass()
zgodnie z opisem w odpowiedzi Davida Wooda .Zobacz ten post. Rodzaj Java Generic jako argument dla GSON
Mam na to lepsze rozwiązanie. Oto klasa opakowania dla listy, dzięki czemu opakowanie może przechowywać dokładnie typ listy.
A potem kod może być prosty:
źródło
mEntity.rulePattern
?Ponieważ
Gson 2.8
możemy stworzyć funkcję util jakPrzykład użycia
źródło
TypeToken#getParameterized
wygląda o wiele lepiej niż hack z anonimową podklasąWep, kolejny sposób na osiągnięcie tego samego rezultatu. Używamy go ze względu na jego czytelność.
Zamiast robić to trudne do odczytania zdanie:
Utwórz pustą klasę, która rozszerza listę twojego obiektu:
I użyj go podczas analizowania JSON:
źródło
W przypadku Kotlin po prostu:
lub tutaj jest przydatna funkcja:
Następnie, aby użyć:
źródło
inline fun <reified T> buildType() = object : TypeToken<T>() {}.type!!
i wywołaj go z typem listy:buildType<List<YourMagicObject>>()
buildType
a także wywołujesz funkcję z typem ogólnym? Czy to literówka? - Spowoduje to utworzenie ArrayList <ArrayList <YourMagicObject>>Przykład:
źródło
DevNG
powyższej odpowiedzi, napisanej 2 lata wcześniej: stackoverflow.com/a/17300003/1339923 (i przeczytaj tę odpowiedź na zastrzeżenia do tego podejścia)Odpowiadając na moje pierwotne pytanie, zaakceptowałem odpowiedź doc_180, ale jeśli ktoś ponownie napotka ten problem, odpowiem również na drugą połowę mojego pytania:
Opisany przeze mnie błąd NullPointerError nie miał nic wspólnego z samą listą, ale z jej zawartością!
Klasa „MyClass” nie miała konstruktora „bez argumentów” i żadna z nich nie miała swojej nadklasy. Po dodaniu prostego konstruktora „MyClass ()” do MyClass i jego nadklasy wszystko działało dobrze, łącznie z serializacją listy i deserializacją, zgodnie z sugestią doc_180.
źródło
Oto rozwiązanie, które działa z dynamicznie zdefiniowanym typem. Sztuką jest stworzenie odpowiedniego typu tablicy za pomocą Array.newInstance ().
źródło
class.cast()
uniknął niesprawdzonego ostrzeżenia spowodowanego przesyłaniem do(T)
. Lub jeszcze lepiej, nie przejmuj się rzutowaniem i użyj czegoś takiego jakArrays.asList()
konwersja z tablicy na aList<T>
. Ponadto nie trzeba podawać długości doArray.newInstance()
- tablica o rozmiarze zero będzie wystarczająca do wywołaniagetClass()
.Chcę dodać jeszcze jedną możliwość. Jeśli nie chcesz używać TypeToken i chcesz przekonwertować tablicę obiektów json na ArrayList, możesz postępować w ten sposób:
Jeśli twoja struktura json jest podobna:
}
a twoja struktura klas wygląda następująco:
możesz to parsować w następujący sposób:
Teraz możesz uzyskać dostęp do każdego elementu obiektu className.
źródło
Zobacz przykład 2, aby zapoznać się z klasą Gson dla klasy „Type”.
Przykład 1: W tym dezilateResturant użyliśmy tablicy Employee [] i uzyskaliśmy szczegóły
Przykład 2:
źródło
Podobała mi się odpowiedź z kays1, ale nie mogłem jej zaimplementować. Więc zbudowałem własną wersję, korzystając z jego koncepcji.
Stosowanie:
źródło
W moim przypadku odpowiedź @ uncaught_exceptions nie zadziałała, musiałem użyć
List.class
zamiastjava.lang.reflect.Type
:źródło