Egy lista sorosítása és deszerializálása a Gson segítségével

1. Bemutatkozás

Ebben az oktatóanyagban néhány fejlett sorosítási és deserializációs esetet tárunk fel Lista a Google Gson könyvtárának használatával.

2. Objektumok listája

Az egyik általános használati eset a POJO-k listájának sorosítása és deszerializálása.

Fontolja meg az osztályt:

nyilvános osztály MyClass {private int id; privát karakterlánc neve; public MyClass (int id, String name) {this.id = id; ez.név = név; } // szerelők és beállítók}

Így sorosítanánk Lista:

@Test public void givenListOfMyClass_whenSerializing_thenCorrect () {List list = Arrays.asList (new MyClass (1, "name1"), new MyClass (2, "name2")); Gson gson = új Gson (); Karakterlánc jsonString = gson.toJson (lista); String várhatóString = "[{\" id \ ": 1, \" név \ ": \" név1 \ "}, {\" id \ ": 2, \" név \ ": \" név2 \ "}]" ; assertEquals (vártString, jsonString); }

Mint láthatjuk, a szerializálás meglehetősen egyszerű.

A deszerializáció azonban trükkös. Ennek helytelen módja:

@Test (várható = ClassCastException.class) public void givenJsonString_whenIncorrectDeserializing_thenThrowClassCastException () {String inputString = "[{\" id \ ": 1, \" name \ ": \" name1 \ "}, {\" id \ ": 2 , \ "név \": \ "név2 \"}] "; Gson gson = új Gson (); List outputList = gson.fromJson (inputString, ArrayList.class); assertEquals (1, outputList.get (0) .getId ()); }

Itt, bár kapnánk egy Lista a második méret, a deszerializáció után, ez nem lenne a Lista nak,-nek Az osztályom. Ezért a 6. sor dob ClassCastException.

A Gson sorosíthatja az önkényes objektumok gyűjteményét, de az adatokat nem képes deserializálni további információk nélkül. Ez azért van, mert a felhasználónak nincs módja megadni a kapott objektum típusát. Ehelyett, miközben deserializálódik, a Gyűjtemény meghatározott, általános típusúnak kell lennie.

A deserializálás helyes módja Lista lenne:

@Test public void givenJsonString_whenDeserializing_thenReturnListOfMyClass () {String inputString = "[{\" id \ ": 1, \" name \ ": \" name1 \ "}, {\" id \ ": 2, \" name \ ": \ "név2 \"}] "; List inputList = tömbök.asList (új MyClass (1, "név1"), új MyClass (2, "név2")); Típus listOfMyClassObject = új TypeToken() {} .getType (); Gson gson = új Gson (); List outputList = gson.fromJson (inputString, listOfMyClassObject); assertEquals (inputList, outputList); }

Itt, a Gson's-t használjuk TypeToken a deserializálandó helyes típus meghatározása - Tömb lista. Az idióma megkapta a listOfMyClassObject valójában meghatároz egy anonim helyi metódust tartalmazó belső osztályt getType () amely a teljesen paraméterezett típust adja vissza.

3. Polimorf objektumok listája

3.1. A probléma

Vegyünk egy példát az állatok osztályhierarchiájára:

állat absztrakt osztály állat {// ...} nyilvános osztály kutya kiterjeszti az állatot {// ...} nyilvános osztály tehén kiterjeszti az állatot {// ...}

Hogyan sorosítjuk és deserializáljuk Lista? Használhatnánk TypeToken mint az előző szakaszban használtuk. Gson azonban még mindig nem tudja kitalálni a listában tárolt objektumok konkrét adattípusát.

3.2. Az Custom Deserializer használata

Ennek megoldásának egyik módja az, hogy típusinformációkat ad hozzá a sorosított JSON-hoz. Tiszteletben tartjuk az ilyen típusú információkat a JSON deserializáció során. Ehhez meg kell írnunk a saját egyedi sorosítónkat és deserializálónkat.

Először bemutatunk egy újat Húr nevű mező típus az alaposztályban Állat. Tárolja az osztály egyszerű nevét, amelyhez tartozik.

Vessünk egy pillantást a minta osztályainkra:

public absztrakt osztály Animal {public String type = "Animal"; }
public class Kutya kiterjeszti Animal {private String petName; nyilvános kutya () {petName = "Milo"; type = "Kutya"; } // szerelők és beállítók}
nyilvános osztály Tehén kiterjeszti Állat {Magánhúr fajta; public Cow () {breed = "Jersey"; type = "Tehén"; } // szerelők és beállítók}

A szerializálás továbbra is működni fog, az eddigi problémák nélkül:

@Test public void givenPolymorphicList_whenSerializeWithTypeAdapter_thenCorrect () {String várhatóString = "[{\" petName \ ": \" Milo \ ", \" type \ ": \" Dog \ "}, {\" breed \ ": \" Jersey \ " ", \" type \ ": \" Tehén \ "}]"; List inList = new ArrayList (); inList.add (új kutya ()); inList.add (új Tehén ()); Karakterlánc jsonString = új Gson (). ToJson (inList); assertEquals (vártString, jsonString); }

A lista deserializálásához meg kell adnunk egy egyedi deserializer-t:

public class AnimalDeserializer megvalósítja a JsonDeserializer {private String animalTypeElementName; Gson gson magánember; privát térkép animalTypeRegistry; public AnimalDeserializer (String animalTypeElementName) {this.animalTypeElementName = animalTypeElementName; this.gson = új Gson (); this.animalTypeRegistry = new HashMap (); } public void registerBarnType (String animalTypeName, Class animalType) {animalTypeRegistry.put (animalTypeName, animalType); } public Animal deserialize (JsonElement json, Type typeOfT, JsonDeserializationContext context) {JsonObject animalObject = json.getAsJsonObject (); JsonElement animalTypeElement = animalObject.get (animalTypeElementName); Class animalType = animalTypeRegistry.get (animalTypeElement.getAsString ()); return gson.fromJson (animalObject, animalType); }}

Itt a animalTypeRegistry A map fenntartja az osztálynév és az osztálytípus közötti leképezést.

A deszerializáció során először az újonnan hozzáadottakat vonjuk ki típus terület. Ennek az értéknek a felhasználásával keresünk egy animalTypeRegistry térképet a konkrét adattípus megszerzéséhez. Ezt az adattípust továbbítják a tólJson ().

Nézzük meg, hogyan kell használni az egyedi deserializerünket:

@Test public void givenPolymorphicList_whenDeserializeWithTypeAdapter_thenCorrect () {String inputString = "[{\" petName \ ": \" Milo \ ", \" type \ ": \" Dog \ "}, {\" breed \ ": \" Jersey \ " ", \" type \ ": \" Tehén \ "}]"; AnimalDeserializer deserializer = új AnimalDeserializer ("típus"); deserializer.registerBarnType ("Kutya", Kutya.osztály); deserializer.registerBarnType ("Tehén", Tehén.osztály); Gson gson = new GsonBuilder () .registerTypeAdapter (Animal.class, deserializer) .create (); List outList = gson.fromJson (inputString, új TypeToken() {}. getType ()); assertEquals (2, outList.size ()); assertTrue (outList.get (0) Dogof példánya); assertTrue (outList.get (1) Tehén példánya); }

3.3. Használata RuntimeTypeAdapterFactory

Az egyéni deserializer írásának alternatívája a RuntimeTypeAdapterFactory osztály van jelen a Gson forráskódban. Azonban, a könyvtár nem teszi hozzáférhetővé a felhasználó számára. Ezért létre kell hoznunk az osztály egy példányát a Java projektünkben.

Ha ez megtörtént, használhatjuk felsorolásunk deszerializálására:

@Test public void givenPolymorphicList_whenDeserializeWithRuntimeTypeAdapter_thenCorrect () {String inputString = "[{\" petName \ ": \" Milo \ ", \" type \ ": \" Dog \ "}, {\" breed \ ": \" Jersey \ " ", \" type \ ": \" Tehén \ "}]"; Type listOfAnimals = new TypeToken() {}. getType (); RuntimeTypeAdapterFactory adapter = RuntimeTypeAdapterFactory.of (Animal.class, "type") .registerSubtype (Dog.class) .registerSubtype (Cow.class); Gson gson = new GsonBuilder (). RegisterTypeAdapterFactory (adapter) .create (); List outList = gson.fromJson (inputString, listOfAnimals); assertEquals (2, outList.size ()); assertTrue (outList.get (0) Dogof példánya); assertTrue (outList.get (1) Tehén példánya); }

Vegye figyelembe, hogy a mögöttes mechanizmus továbbra is ugyanaz.

A szerializálás során még be kell vezetnünk a típusinformációkat. A típusinformáció később felhasználható a deserializáció során. Ezért a mező típus továbbra is minden osztályban szükséges, hogy ez a megoldás működjön. Csak nem kell megírnunk a saját deserializálónkat.

RuntimeTypeAdapterFactory biztosítja a megfelelő típusú adaptert a neki átadott mezőnév és a regisztrált altípusok alapján.

4. Következtetés

Ebben a cikkben azt láttuk, hogyan lehet az objektumok listáját sorosítani és deszerializálni a Gson segítségével.

Szokás szerint a kód elérhető a GitHubon.


$config[zx-auto] not found$config[zx-overlay] not found