Mam ciąg json, który powinienem zdeserializować do następującej klasy
class Data <T> {
int found;
Class<T> hits
}
Jak mam to zrobić? To jest zwykły sposób
mapper.readValue(jsonString, Data.class);
Ale jak mam wspomnieć, co oznacza T?
Odpowiedzi:
Musisz utworzyć
TypeReference
obiekt dla każdego używanego typu ogólnego i użyć go do deserializacji. Na przykład -źródło
Data<T>
, to NIE jest typ. Musisz określić aktualną klasę; w przeciwnym razie jest taki sam jakData<Object>
.TypeReference
? czy tocom.fasterxml.jackson.core.type
jestNie możesz tego zrobić: musisz określić typ w pełni rozwiązany, na przykład
Data<MyType>
.T
jest tylko zmienną i bez znaczenia.Ale jeśli masz na myśli, że
T
będzie znany, tylko nie statycznie, musisz utworzyć odpowiednikTypeReference
dynamicznie. Inne przywoływane pytania mogą już o tym wspominać, ale powinno to wyglądać mniej więcej tak:źródło
TypeReference
: Nareturn mapper.readValue(json, clazz);
czym dokładnie polega problem?TypeFactory
… Zmienię swoją odpowiedź.Pierwszą rzeczą, którą musisz zrobić, jest serializacja, a następnie możesz przeprowadzić deserializację.
więc kiedy robisz serializację, powinieneś użyć,
@JsonTypeInfo
aby pozwolić Jacksonowi zapisywać informacje o klasach do twoich danych JSON. Oto co możesz zrobić:Następnie, kiedy deserializujesz, zobaczysz, że jackson zdeserializował twoje dane do klasy, w której trafia twoja zmienna, w rzeczywistości w czasie wykonywania.
źródło
Dla klasy Data <>
źródło
Po prostu napisz metodę statyczną w klasie Util. Czytam Json z pliku. możesz nadać String również readValue
Stosowanie:
źródło
Możesz umieścić go w innej klasie, która zna typ twojego ogólnego typu.
Na przykład,
Tutaj Coś jest konkretnym typem. Potrzebujesz opakowania na zreifikowany typ. W przeciwnym razie Jackson nie wie, jakie obiekty tworzyć.
źródło
Ciąg JSON, który musi zostać zdeserializowany, będzie musiał zawierać informacje o typie parametru
T
.Będziesz musiał umieścić adnotacje Jacksona na każdej klasie, która może być przekazana jako parametr
T
do klasy,Data
abyT
Jackson mógł odczytać informacje o typie parametru z / zapisać do łańcucha JSON.Załóżmy, że
T
może to być dowolna klasa, która rozszerza klasę abstrakcyjnąResult
.Gdy każda klasa (lub ich wspólny nadtyp), która może zostać przekazana jako parametr,
T
zostanie opatrzona adnotacją, Jackson umieści informacje o parametrzeT
w JSON. Taki JSON można następnie deserializować bez znajomości parametruT
w czasie kompilacji.Ten link do dokumentacji Jacksona mówi o deserializacji polimorficznej, ale jest przydatny również w przypadku tego pytania.
źródło
Od Jackson 2.5, elegancki sposób rozwiązania tego problemu polega na użyciu TypeFactory.constructParametricType (Class parametized, Class ... parameterClasses) , która pozwala na proste zdefiniowanie Jacksona
JavaType
przez określenie sparametryzowanej klasy i jej sparametryzowanych typów.Przypuśćmy, że chcesz przeprowadzić deserializację
Data<String>
, możesz wykonać:Zwróć uwagę, że gdyby klasa zadeklarowała wiele sparametryzowanych typów, nie byłoby to naprawdę trudniejsze:
Moglibyśmy zrobić :
źródło
źródło
jeśli używasz scala i znasz typ ogólny w czasie kompilacji, ale nie chcesz ręcznie przekazywać TypeReference wszędzie we wszystkich swoich api lachach, możesz użyć następującego kodu (z jacksonem 2.9.5):
którego można użyć w ten sposób:
źródło
Aby deserializować ogólny ciąg JSON do obiektu Java za pomocą Jacksona, potrzebujesz:
Aby zdefiniować klasę JSON.
Wykonaj mapowanie atrybutów.
Ostateczny kod, przetestowany i gotowy do użycia:
Ważne:
@JsonAnySetter
adnotacja jest obowiązkowa, zapewnia ogólne analizowanie i wypełnianie JSON.Bardziej skomplikowane przypadki z zagnieżdżonymi tablicami można znaleźć w dokumencie Baeldung: https://www.baeldung.com/jackson-mapping-dynamic-object
źródło
Przykład niezbyt dobrej, ale prostej decyzji (nie tylko dla Jacksona, ale także dla Spring RestTemplate itp.):
źródło