Pozivanje zadanog serializatora iz Custom Serializera u Jacksonu

1. Uvod

Serijalizacija naše cjelovite strukture podataka u JSON koristeći točan jedan-na-jedan prikaz svih polja možda ponekad nije prikladna ili jednostavno ne mora biti ono što želimo. Umjesto toga, možda bismo željeli stvoriti prošireni ili pojednostavljeni prikaz naših podataka. Tu dolaze u obzir prilagođeni Jacksonovi serializatori.

Međutim, implementacija prilagođenog serializatora može biti dosadna, pogotovo ako objekti našeg modela imaju puno polja, zbirki ili ugniježđenih objekata. Srećom, biblioteka Jackson ima nekoliko odredbi koje ovaj posao mogu učiniti puno jednostavnijim.

U ovom ćemo kratkom vodiču pogledati prilagođene Jacksonove serializatore i pokazati kako pristupiti zadanim serializatorima unutar prilagođenog serializatora.

2. Uzorak modela podataka

Prije nego što uđemo u prilagodbu Jacksona, pogledajmo naš uzorak Mapa razred koji želimo serializirati:

mapa javne klase {private Long id; privatni naziv niza; privatni vlasnik niza; privatno Datum kreiranja; privatno Datum izmjene; privatno Datum lastAccess; datoteke privatnog popisa = novi ArrayList (); // standardni geteri i postavljači} 

I Datoteka klasa, koja se definira kao Popis unutar našeg Mapa razred:

datoteka javne klase {private Long id; privatni naziv niza; // standardni geteri i postavljači} 

3. Prilagođeni serializatori u Jacksonu

Glavna prednost korištenja prilagođenih serializatora je u tome što ne moramo mijenjati strukturu klase. Plus, lako možemo odvojiti svoje očekivano ponašanje od samog razreda.

Dakle, zamislimo da želimo smanjen pogled na naše Mapa razred:

{"name": "Korijenska mapa", "files": [{"id": 1, "name": "File 1"}, {"id": 2, "name": "File 2"}]} 

Kao što ćemo vidjeti u sljedećim odjeljcima, postoji nekoliko načina na koje možemo postići željeni rezultat u Jacksonu.

3.1. Pristup grube sile

Prvo, bez korištenja Jacksonovih zadanih serializatora, možemo stvoriti prilagođeni serializator u kojem sami radimo sve teške poslove.

Stvorimo prilagođeni serializator za naš Mapa razred da to postigne:

javna klasa FolderJsonSerializer proširuje StdSerializer {public FolderJsonSerializer () {super (Folder.class); } @Override public void serialize (vrijednost mape, JsonGenerator gen, dobavljač SerializerProvider) baca IOException {gen.writeStartObject (); gen.writeStringField ("ime", vrijednost.getName ()); gen.writeArrayFieldStart ("datoteke"); za (Datoteka datoteke: value.getFiles ()) {gen.writeStartObject (); gen.writeNumberField ("id", file.getId ()); gen.writeStringField ("ime", file.getName ()); gen.writeEndObject (); } gen.writeEndArray (); gen.writeEndObject (); }}

Dakle, možemo serializirati svoje Mapa klase na smanjeni prikaz koji sadrži samo polja koja želimo.

3.2. Korištenje interne ObjectMapper

Iako nam prilagođeni serializatori pružaju fleksibilnost detaljnog mijenjanja svakog svojstva, posao možemo olakšati ponovna upotreba Jacksonovih zadanih serializatora.

Jedan od načina korištenja zadanih serializatora je pristup internom ObjectMapper razred:

@Override public void serialize (Vrijednost mape, JsonGenerator gen, SerializerProvider provider) baca IOException {gen.writeStartObject (); gen.writeStringField ("ime", vrijednost.getName ()); ObjectMapper mapper = (ObjectMapper) gen.getCodec (); gen.writeFieldName ("datoteke"); Niz stringValue = mapper.writeValueAsString (value.getFiles ()); gen.writeRawValue (stringValue); gen.writeEndObject (); } 

Dakle, Jackson jednostavno rješava dizanje teške ruke serializacijom Popis od Datoteka objekata, a tada će i naš izlaz biti isti.

3.3. Koristeći SerializerProvider

Drugi način pozivanja zadanih serializatora je korištenje SerializerProvider. Stoga postupak delegiramo zadanom serializatoru tipa Datoteka.

A sada, pojednostavnimo naš kod uz pomoć SerializerProvider:

@Override public void serialize (Vrijednost mape, JsonGenerator gen, SerializerProvider provider) baca IOException {gen.writeStartObject (); gen.writeStringField ("ime", vrijednost.getName ()); provider.defaultSerializeField ("datoteke", value.getFiles (), gen); gen.writeEndObject (); } 

I, kao i prije, dobivamo isti izlaz.

4. Mogući rekurzijski problem

Ovisno o slučaju korištenja, možda ćemo morati proširiti svoje serializirane podatke tako što ćemo uključiti više detalja za Mapa. Ovo bi moglo biti za naslijeđeni sustav ili vanjska aplikacija koju treba integrirati i koju nemamo priliku izmijeniti.

Promijenimo svoj serializator kako bismo stvorili pojedinosti polje za naše serializirane podatke da jednostavno izlože sva polja Mapa razred:

@Override public void serialize (Vrijednost mape, JsonGenerator gen, SerializerProvider provider) baca IOException {gen.writeStartObject (); gen.writeStringField ("ime", vrijednost.getName ()); provider.defaultSerializeField ("datoteke", value.getFiles (), gen); // ovaj redak uzrokuje izuzeće provider.defaultSerializeField ("detalji", vrijednost, gen); gen.writeEndObject (); } 

Ovaj put dobivamo StackOverflowError iznimka.

Kad definiramo prilagođeni serializator, Jackson interno nadjača original BeanSerializer primjer koji je stvoren za tip Mapa. Slijedom toga, naša SerializerProvider svaki put pronađe prilagođeni serializator, umjesto zadanog, i to uzrokuje beskonačnu petlju.

Pa, kako da riješimo ovaj problem? U sljedećem ćemo odjeljku vidjeti jedno korisno rješenje za ovaj scenarij.

5. Korištenje BeanSerializerModifier

Moguće zaobilazno rješenje je korištenje BeanSerializerModifierza pohranu zadanog serializatora za tip Mapaprije nego što ga Jackson interno nadjača.

Izmijenimo naš serializator i dodajte dodatno polje - defaultSerializer:

privatni konačni JsonSerializer defaultSerializer; javni FolderJsonSerializer (JsonSerializer defaultSerializer) {super (Folder.class); this.defaultSerializer = defaultSerializer; } 

Dalje ćemo stvoriti implementaciju BeanSerializerModifier za prosljeđivanje zadanog serializatora:

javna klasa FolderBeanSerializerModifier proširuje BeanSerializerModifier {@Override javni JsonSerializer modifySerializer (SerializationConfig config, BeanDescription beanDesc, JsonSerializer serializer) {if (beanDesc.getBeanClass (). equals (Folder.erialiaSerseJSlayerJaclajsJSolderSlayerJaclassJ } return serializer; }} 

Sada moramo registrirati svoj BeanSerializerModifier kao modul za njegovo funkcioniranje:

Mapa ObjectMapper = novi ObjectMapper (); Modul SimpleModule = novi SimpleModule (); module.setSerializerModifier (novi FolderBeanSerializerModifier ()); mapper.registerModule (modul); 

Zatim koristimo defaultSerializer za pojedinosti polje:

@Override public void serialize (Vrijednost mape, JsonGenerator gen, SerializerProvider provider) baca IOException {gen.writeStartObject (); gen.writeStringField ("ime", vrijednost.getName ()); provider.defaultSerializeField ("datoteke", value.getFiles (), gen); gen.writeFieldName ("detalji"); defaultSerializer.serialize (vrijednost, gen, dobavljač); gen.writeEndObject (); } 

Na kraju, možda ćemo htjeti ukloniti datoteke polje od pojedinosti budući da ga već zasebno zapisujemo u serializirane podatke.

Dakle, mi jednostavno ignoriramo datoteke polje u našem Mapa razred:

@JsonIgnore datoteke privatnog popisa = novi ArrayList (); 

Napokon, problem je riješen i dobivamo i očekivani rezultat:

{"name": "Korijenska mapa", "files": [{"id": 1, "name": "File 1"}, {"id": 2, "name": "File 2"}], "detalji": {"id": 1, "name": "Korijenska mapa", "owner": "root", "created": 1565203657164, "modified": 1565203657164, "lastAccess": 1565203657164}} 

6. Zaključak

U ovom vodiču, naučili smo kako nazvati zadane serializatore unutar prilagođenog serializatora u Jackson Library.

Kao i uvijek, svi primjeri koda korišteni u ovom vodiču dostupni su na GitHub-u.


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