Korzystam z interfejsu API z mojej aplikacji na Androida, a wszystkie odpowiedzi JSON są takie:
{
'status': 'OK',
'reason': 'Everything was fine',
'content': {
< some data here >
}
Problemem jest to, że wszyscy moi POJOs mieć status
, reason
pola, a wewnątrz content
pola jest prawdziwym POJO chcę.
Czy istnieje sposób na stworzenie niestandardowego konwertera Gson, który wyodrębnia zawsze content
pole, więc retrofit zwraca odpowiednie POJO?
Odpowiedzi:
Możesz napisać niestandardowy deserializator, który zwraca osadzony obiekt.
Powiedzmy, że Twój JSON to:
Miałbyś wtedy
Content
POJO:Następnie piszesz deserializator:
Teraz, jeśli skonstruować
Gson
zGsonBuilder
i zarejestrować Deserializator:Możesz deserializować swój JSON bezpośrednio na
Content
:Edytuj, aby dodać z komentarzy:
Jeśli masz różne typy wiadomości, ale wszystkie mają pole „zawartość”, możesz ustawić deserializator jako ogólny, wykonując:
Musisz tylko zarejestrować instancję dla każdego ze swoich typów:
Po wywołaniu
.fromJson()
typ jest przenoszony do deserializatora, więc powinien działać dla wszystkich typów.I wreszcie podczas tworzenia instancji typu Retrofit:
źródło
setConverter(new GsonConverter(gson))
wRestAdapter.Builder
klasie RetrofitPerson.class
iList<Person>.class
/Person[].class
z oddzielnym Deserializerem?Rozwiązanie @ BrianRoach jest właściwym rozwiązaniem. Warto zauważyć, że w szczególnym przypadku, gdy masz zagnieżdżone obiekty niestandardowe, które wymagają niestandardowego
TypeAdapter
, musisz zarejestrowaćTypeAdapter
je w nowej instancji GSON , w przeciwnym razie drugaTypeAdapter
nigdy nie zostanie wywołana. Dzieje się tak, ponieważ tworzymy nowyGson
instancję w naszym niestandardowym deserializatorze.Na przykład, jeśli masz następujący plik json:
I chciałeś, aby ten JSON został zmapowany do następujących obiektów:
Musisz zarejestrować
SubContent
plikTypeAdapter
. Aby być bardziej niezawodnym, możesz wykonać następujące czynności:a następnie utwórz go w ten sposób:
Można to z łatwością wykorzystać również w przypadku zagnieżdżonego przypadku „content”, po prostu przekazując nową instancję
MyDeserializer
z wartościami null.źródło
java.lang.reflect.Type
Trochę późno, ale mam nadzieję, że to komuś pomoże.
Po prostu utwórz następujący TypeAdapterFactory.
i dodaj go do swojego kreatora GSON:
lub
źródło
jsonElement
? Tak jak macontent
,content1
itpMiałem ten sam problem kilka dni temu. Rozwiązałem to za pomocą klasy opakowania odpowiedzi i transformatora RxJava, co moim zdaniem jest dość elastycznym rozwiązaniem:
Obwoluta:
Niestandardowy wyjątek do zgłoszenia, gdy stan nie jest OK:
Transformator Rx:
Przykładowe użycie:
Mój temat: Retrofit 2 RxJava - Gson - "Globalna" deserializacja, zmiana typu odpowiedzi
źródło
Kontynuując pomysł Briana, ponieważ prawie zawsze mamy wiele zasobów REST, z których każdy ma swój własny katalog główny, przydatne może być uogólnienie deserializacji:
Następnie, aby przeanalizować przykładowy ładunek z góry, możemy zarejestrować deserializator GSON:
źródło
Lepszym rozwiązaniem mogłoby być to ...
Następnie zdefiniuj swoją usługę w ten sposób.
źródło
Zgodnie z odpowiedzią @Brian Roach i @rafakob zrobiłem to w następujący sposób
Odpowiedź JSON z serwera
Wspólna klasa obsługi danych
Niestandardowy serializator
Obiekt Gson
Połączenie API
źródło
To jest to samo rozwiązanie co @AYarulin, ale załóżmy, że nazwa klasy to nazwa klucza JSON. W ten sposób wystarczy podać nazwę klasy.
Następnie, aby przeanalizować przykładowy ładunek z góry, możemy zarejestrować deserializator GSON. Jest to problematyczne, ponieważ w kluczu rozróżniana jest wielkość liter, więc wielkość liter w nazwie klasy musi odpowiadać wielkości liter w kluczu JSON.
źródło
Oto wersja Kotlina oparta na odpowiedziach Briana Roacha i AYarulina.
źródło
W moim przypadku klucz „content” zmieniłby się dla każdej odpowiedzi. Przykład:
W takich przypadkach użyłem podobnego rozwiązania, jak wymienione powyżej, ale musiałem je poprawić. Możesz zobaczyć sedno tutaj . Jest trochę za duży, aby opublikować go tutaj w SOF.
Adnotacja
@InnerKey("content")
jest używana, a reszta kodu ma ułatwić jej użycie z Gson.źródło
Nie zapomnij
@SerializedName
i@Expose
adnotacje dla wszystkich członków klasy i członków klasy Wewnętrzna że większość deserializacji z JSON przez GSON.Spójrz na https://stackoverflow.com/a/40239512/1676736
źródło
Kolejne proste rozwiązanie:
źródło