Volanie predvoleného serializátora z vlastného serializátora v Jackson

1. Úvod

Serializácia našej kompletnej dátovej štruktúry na JSON pomocou presného vzájomného znázornenia všetkých polí nemusí byť niekedy vhodné alebo jednoducho nemusí byť to, čo chceme. Namiesto toho možno budeme chcieť vytvoriť rozšírené alebo zjednodušené zobrazenie našich údajov. To je miesto, kde prichádzajú do úvahy vlastné Jacksonove serializátory.

Implementácia vlastného serializátora však môže byť zdĺhavá, najmä ak majú naše modelové objekty veľa polí, kolekcií alebo vnorených objektov. Našťastie má Jacksonova knižnica niekoľko ustanovení, ktoré môžu túto prácu výrazne zjednodušiť.

V tejto krátkej príručke sa pozrieme na vlastné Jacksonove serializátory a ukážeme si ich ako získať prístup k predvoleným serializátorom vo vnútri vlastného serializátora -.

2. Vzorový dátový model

Predtým, ako sa ponoríme do prispôsobenia Jacksona, pozrime sa na našu ukážku Priečinok trieda, ktorú chceme serializovať:

public class Priečinok {private Long id; súkromné ​​meno reťazca; súkromný vlastník reťazca; súkromné ​​Dátum vytvorenia; súkromné ​​Dátum úpravy; súkromné ​​Dátum lastAccess; súkromné ​​zoznamové súbory = nový ArrayList (); // štandardné getre a setre} 

A Súbor trieda, ktorá je definovaná ako a Zoznam vo vnútri nášho Priečinok trieda:

public class File {private Long id; súkromné ​​meno reťazca; // štandardné getre a setre} 

3. Vlastné serializátory v Jackson

Hlavnou výhodou použitia vlastných serializátorov je, že nemusíme upravovať štruktúru našej triedy. Plus, môžeme ľahko oddeliť naše očakávané správanie od samotnej triedy.

Predstavme si teda, že chceme mať obmedzený pohľad na svoje Priečinok trieda:

{"name": "Root Folder", "files": [{"id": 1, "name": "File 1"}, {"id": 2, "name": "File 2"}]} 

Ako uvidíme v ďalších častiach, existuje niekoľko spôsobov, ako dosiahnuť požadovaný výstup v Jackson.

3.1. Prístup hrubou silou

Najskôr bez použitia Jacksonových predvolených serializátorov môžeme vytvoriť vlastný serializátor, v ktorom vykonávame všetky ťažké práce sami.

Vytvorme si pre nás vlastný serializátor Priečinok triedy na dosiahnutie tohto cieľa:

public class FolderJsonSerializer rozširuje StdSerializer {public FolderJsonSerializer () {super (Folder.class); } @Override public void serialize (hodnota priečinka, JsonGenerator gen, poskytovateľ SerializerProvider) hodí IOException {gen.writeStartObject (); gen.writeStringField ("meno", hodnota.getName ()); gen.writeArrayFieldStart ("súbory"); pre (File file: value.getFiles ()) {gen.writeStartObject (); gen.writeNumberField ("id", file.getId ()); gen.writeStringField ("meno", file.getName ()); gen.writeEndObject (); } gen.writeEndArray (); gen.writeEndObject (); }}

Môžeme teda serializovať naše Priečinok triedy na zmenšené zobrazenie obsahujúce iba polia, ktoré chceme.

3.2. Pomocou internej ObjectMapper

Aj keď nám vlastné serializátory poskytujú flexibilitu pri podrobnom pozmeňovaní každej vlastnosti, môžeme si tým uľahčiť prácu opätovné použitie Jacksonových predvolených serializátorov.

Jedným zo spôsobov použitia predvolených serializátorov je prístup k internému ObjectMapper trieda:

@Override public void serialize (hodnota priečinka, JsonGenerator gen, poskytovateľ SerializerProvider) hodí IOException {gen.writeStartObject (); gen.writeStringField ("meno", hodnota.getName ()); ObjectMapper mapper = (ObjectMapper) gen.getCodec (); gen.writeFieldName ("súbory"); Reťazec stringValue = mapper.writeValueAsString (value.getFiles ()); gen.writeRawValue (stringValue); gen.writeEndObject (); } 

Takže Jackson jednoducho zvládne ťažké zdvíhanie pomocou serializácie Zoznam z Súbor objekty, a potom bude náš výstup rovnaký.

3.3. Použitím SerializerProvider

Ďalším spôsobom, ako zavolať predvolené serializátory, je použitie súboru SerializerProvider. Preto delegujeme proces na predvolený serializátor typu Súbor.

Poďme si teraz trochu zjednodušiť náš kód pomocou SerializerProvider:

@Override public void serialize (hodnota priečinka, JsonGenerator gen, poskytovateľ SerializerProvider) hodí IOException {gen.writeStartObject (); gen.writeStringField ("meno", hodnota.getName ()); provider.defaultSerializeField ("súbory", value.getFiles (), gen); gen.writeEndObject (); } 

Rovnako ako predtým dostávame rovnaký výstup.

4. Možný problém rekurzie

V závislosti od prípadu použitia bude možno potrebné rozšíriť naše serializované údaje o ďalšie podrobnosti pre Priečinok. Toto by mohlo byť pre integrovaný starší systém alebo externá aplikácia, ktorú nemáme šancu upraviť.

Zmeňme náš serializátor a vytvorme podrobnosti pole pre naše serializované údaje, aby sa jednoducho odkryli všetky polia súboru Priečinok trieda:

@Override public void serialize (hodnota priečinka, JsonGenerator gen, poskytovateľ SerializerProvider) hodí IOException {gen.writeStartObject (); gen.writeStringField ("meno", hodnota.getName ()); provider.defaultSerializeField ("súbory", value.getFiles (), gen); // tento riadok spôsobí výnimku provider.defaultSerializeField ("details", value, gen); gen.writeEndObject (); } 

Tentokrát dostávame a StackOverflowError výnimkou.

Keď definujeme vlastný serializátor, Jackson interne prepíše originál BeanSerializer inštancia ktorý je pre daný typ vytvorený Priečinok. V dôsledku toho naše SerializerProvider nájde zakaždým prispôsobený serializátor namiesto predvoleného, ​​čo spôsobí nekonečnú slučku.

Ako teda vyriešiť tento problém? Jedno použiteľné riešenie pre tento scenár uvidíme v nasledujúcej časti.

5. Používanie BeanSerializerModifier

Možné riešenie je použitie BeanSerializerModifierna uloženie predvoleného serializátora pre typ Priečinokpredtým, ako to Jackson vnútorne prekoná.

Upravme náš serializátor a pridajme ďalšie pole - defaultSerializer:

súkromný konečný JsonSerializer defaultSerializer; public FolderJsonSerializer (JsonSerializer defaultSerializer) {super (Folder.class); this.defaultSerializer = defaultSerializer; } 

Ďalej vytvoríme implementáciu BeanSerializerModifier odovzdať predvolený serializátor:

public class FolderBeanSerializerModifier rozširuje BeanSerializerModifier {@Override public JsonSerializer modifySerializer (SerializationConfig config, BeanDescription beanDesc, JsonSerializer serializer) {if (beanDesc.getBeanClass (). equals (Folder.class) { } návratový serializátor; }} 

Teraz musíme zaregistrovať naše BeanSerializerModifier ako modul, aby to fungovalo:

ObjectMapper mapovač = nový ObjectMapper (); Modul SimpleModule = nový SimpleModule (); module.setSerializerModifier (nový FolderBeanSerializerModifier ()); mapper.registerModule (modul); 

Potom použijeme defaultSerializer pre podrobnosti lúka:

@Override public void serialize (hodnota priečinka, JsonGenerator gen, poskytovateľ SerializerProvider) hodí IOException {gen.writeStartObject (); gen.writeStringField ("meno", hodnota.getName ()); provider.defaultSerializeField ("súbory", value.getFiles (), gen); gen.writeFieldName ("podrobnosti"); defaultSerializer.serialize (hodnota, gen, poskytovateľ); gen.writeEndObject (); } 

Na záver možno budeme chcieť odstrániť súbory pole z podrobnosti keďže to už do serializovaných údajov zapisujeme osobitne.

Takže jednoducho ignorujeme súbory pole v našom Priečinok trieda:

@JsonIgnore súkromné ​​súbory zoznamu = new ArrayList (); 

Nakoniec je problém vyriešený a dostaneme tiež náš očakávaný výstup:

{"name": "Root Folder", "files": [{"id": 1, "name": "File 1"}, {"id": 2, "name": "File 2"}], "details": {"id": 1, "name": "Root Folder", "owner": "root", "created": 1565203657164, "modified": 1565203657164, "lastAccess": 1565203657164}}} 

6. Záver

V tomto návode Naučili sme sa, ako volať predvolené serializátory vo vnútri vlastného serializátora v Jacksonovej knižnici.

Všetky príklady kódov použitých v tomto výučbe sú ako vždy k dispozícii na GitHub.


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