Alapértelmezett Serializer hívása a Jacksoni Custom Serializerből

1. Bemutatkozás

Előfordulhat, hogy a teljes adatstruktúránk JSON-ba történő összesítése a mezők pontos, egy az egyben ábrázolásával néha nem megfelelő, vagy egyszerűen nem megfelelő. Helyette, érdemes létrehozni egy kiterjesztett vagy egyszerűsített nézetet az adatainkról. Itt lépnek színre az egyedi Jackson sorozatszámosítók.

Az egyedi sorosító megvalósítása azonban fárasztó lehet, különösen, ha a modellobjektumainknak sok mezője, gyűjteménye vagy beágyazott objektuma van. Szerencsére a Jackson könyvtár számos rendelkezéssel rendelkezik, amelyek sokkal egyszerűbbé tehetik ezt a munkát.

Ebben a rövid bemutatóban megvizsgáljuk az egyedi Jackson-sorozatokat és bemutatjuk hogyan férhetünk hozzá az alapértelmezett sorosítókhoz egy egyedi sorosítón belül.

2. Minta adatmodell

Mielőtt belevetnénk magunkat Jackson testreszabásába, nézzük meg a mintánkat Mappa osztály, amelyet sorosítani szeretnénk:

public class Mappa {private Long id; privát karakterlánc neve; magánhúr-tulajdonos; privát Létrehozás dátuma; privát Módosítás dátuma; privát Dátum lastAccess; privát lista fájlok = new ArrayList (); // szabványos mérőeszközök és beállítók} 

És a File osztály, amelyet a Lista bennünk Mappa osztály:

public class Fájl {private Long id; privát karakterlánc neve; // szabványos mérőeszközök és beállítók} 

3. Custom Serializer Jackson-ban

Az egyedi szerializálók használatának legfőbb előnye, hogy nem kell módosítanunk az osztályszerkezetünket. Plusz, könnyen elválaszthatjuk elvárt viselkedésünket magától az osztálytól.

Tehát, képzeljük el, hogy csökkentett képet akarunk látni a képünkről Mappa osztály:

{"név": "Gyökér mappa", "fájlok": [{"id": 1, "név": "1. fájl"}, {"id": 2, "név": "2. fájl"}]} 

Amint a következő szakaszokban láthatjuk, többféleképpen érhetjük el a kívánt teljesítményt Jacksonban.

3.1. Brute Force megközelítés

Először is, Jackson alapértelmezett sorosítóinak használata nélkül létrehozhatunk egy egyedi sorosítót, amelyben az összes nehéz feladatot magunk végezzük.

Hozzunk létre egy egyedi sorosítót a sajátunk számára Mappa osztály ennek elérésére:

public class FolderJsonSerializer kiterjeszti a StdSerializer {public FolderJsonSerializer () {super (Folder.class); } @Orride public void serialize (Mappaérték, JsonGenerator gen, SerializerProvider szolgáltató) dobja az IOException {gen.writeStartObject (); gen.writeStringField ("név", érték.getName ()); gen.writeArrayFieldStart ("fájlok"); for (Fájl fájl: value.getFiles ()) {gen.writeStartObject (); gen.writeNumberField ("id", file.getId ()); gen.writeStringField ("név", file.getName ()); gen.writeEndObject (); } gen.writeEndArray (); gen.writeEndObject (); }}

Így sorosíthatjuk a Mappa osztály egy csökkentett nézetre, amely csak a kívánt mezőket tartalmazza.

3.2. A Internal használatával ObjectMapper

Bár az egyedi sorosító készülékek rugalmasságot biztosítanak számunkra, hogy minden tulajdonságot részletesen módosítsunk, megkönnyíthetjük a munkánkat Jackson alapértelmezett sorosítóinak újrafelhasználása.

Az alapértelmezett sorosítók használatának egyik módja a belső elérése ObjectMapper osztály:

@Orride public void serialize (Mappaérték, JsonGenerator gen, SerializerProvider szolgáltató) dobja az IOException {gen.writeStartObject (); gen.writeStringField ("név", érték.getName ()); ObjectMapper mapper = (ObjectMapper) gen.getCodec (); gen.writeFieldName ("fájlok"); String stringValue = mapper.writeValueAsString (value.getFiles ()); gen.writeRawValue (stringValue); gen.writeEndObject (); } 

Tehát Jackson egyszerűen kezeli a nehéz emelést a Lista nak,-nek File objektumok, és akkor a kimenetünk ugyanaz lesz.

3.3. Használata SerializerProvider

Az alapértelmezett sorosítók hívásának másik módja a SerializerProvider. Ezért a folyamatot a típus alapértelmezett sorosítójára delegáljuk File.

Most egyszerűsítsük egy kicsit a kódunkat a segítségével SerializerProvider:

@Orride public void serialize (Mappaérték, JsonGenerator gen, SerializerProvider szolgáltató) dobja az IOException {gen.writeStartObject (); gen.writeStringField ("név", érték.getName ()); szolgáltató.defaultSerializeField ("fájlok", value.getFiles (), gen); gen.writeEndObject (); } 

És ugyanúgy, mint korábban, ugyanazt a kimenetet kapjuk.

4. Lehetséges rekurziós probléma

A felhasználási esettől függően előfordulhat, hogy bővítenünk kell a sorosított adatainkat a következőkkel kapcsolatos további információkkal Mappa. Ez lehet egy olyan régi rendszert vagy egy integrálandó külső alkalmazást, amelynek módosítására nincs esélyünk.

Változtassuk meg a sorozatszerkesztőnket a részletek mező, hogy a sorosított adataink egyszerűen kitegyék a Mappa osztály:

@Orride public void serialize (Mappaérték, JsonGenerator gen, SerializerProvider szolgáltató) dobja az IOException {gen.writeStartObject (); gen.writeStringField ("név", érték.getName ()); szolgáltató.defaultSerializeField ("fájlok", value.getFiles (), gen); // ez a sor kivételt képez a szolgáltató.defaultSerializeField ("részletek", érték, gen); gen.writeEndObject (); } 

Ezúttal a StackOverflowError kivétel.

Amikor meghatározunk egy egyedi sorosítót, Jackson belső módon felülírja az eredetit BeanSerializer példa ami a típushoz jön létre Mappa. Következésképpen a mi SerializerProvider az alapértelmezett helyett minden alkalommal megtalálja a testreszabott sorosítót, és ez végtelen ciklust okoz.

Szóval, hogyan oldjuk meg ezt a problémát? A következő részben egy használható megoldást fogunk látni erre a forgatókönyvre.

5. Használata BeanSerializerModifier

A lehetséges megoldás lehet BeanSerializerModifieraz alapértelmezett sorosító tárolásához a típushoz Mappamielőtt Jackson belsőleg felülírja.

Módosítsuk a sorosítónkat, és adjunk hozzá egy extra mezőt - defaultSerializer:

privát végleges JsonSerializer defaultSerializer; public FolderJsonSerializer (JsonSerializer defaultSerializer) {szuper (Mappaosztály); this.defaultSerializer = defaultSerializer; } 

Ezután létrehozunk egy megvalósítást BeanSerializerModifier az alapértelmezett sorosító átadásához:

A public class FolderBeanSerializerModifier kiterjeszti a BeanSerializerModifier {@Override public JsonSerializer modifySerializer (SerializationConfig config, BeanDescription beanDesc, JsonSerializer serializer) {if (beanDesc.getBeanClass (). equals (Folder.class) (Folder.class) } return sorosító; }} 

Most regisztrálnunk kell BeanSerializerModifier modulként, hogy működjön:

ObjectMapper mapper = új ObjectMapper (); SimpleModule module = new SimpleModule (); module.setSerializerModifier (új FolderBeanSerializerModifier ()); mapper.registerModule (modul); 

Ezután használjuk a defaultSerializer a részletek terület:

@Orride public void serialize (Mappaérték, JsonGenerator gen, SerializerProvider szolgáltató) dobja az IOException {gen.writeStartObject (); gen.writeStringField ("név", érték.getName ()); szolgáltató.defaultSerializeField ("fájlok", value.getFiles (), gen); gen.writeFieldName ("részletek"); defaultSerializer.serialize (érték, gen, szolgáltató); gen.writeEndObject (); } 

Végül érdemes lehet eltávolítani a fájlokat mező a részletek mivel már külön írjuk a sorosított adatokba.

Tehát egyszerűen figyelmen kívül hagyjuk a fájlokat mező a mi Mappa osztály:

@JsonIgnore privát lista fájlok = new ArrayList (); 

Végül a probléma megoldódott, és megkapjuk a várt eredményt is:

{"név": "Gyökér mappa", "fájlok": [{"id": 1, "név": "1. fájl"}, {"id": 2, "név": "2. fájl"}], "részletek": {"id": 1, "név": "Gyökér mappa", "tulajdonos": "gyökér", "létrehozva": 1565203657164, "módosított": 1565203657164, "lastAccess": 1565203657164}} 

6. Következtetés

Ebben az oktatóanyagban megtanultuk, hogyan kell az alapértelmezett sorosítókat hívni a Jackson Könyvtárban egy egyedi sorosítón belül.

Mint mindig, az oktatóanyagban használt összes kódpélda elérhető a GitHubon.