Opkald til standard Serializer fra Custom Serializer i Jackson

1. Introduktion

Serialisering af vores komplette datastruktur til JSON ved hjælp af en nøjagtig en-til-en-repræsentation af alle felterne er muligvis ikke passende nogle gange eller er måske ikke det, vi ønsker. I stedet, Vi vil muligvis oprette en udvidet eller forenklet visning af vores data. Det er her, brugerdefinerede Jackson-serialisatorer kommer i spil.

Imidlertid kan implementering af en brugerdefineret serializer være kedelig, især hvis vores modelobjekter har mange felter, samlinger eller indlejrede objekter. Heldigvis har Jackson-biblioteket flere bestemmelser, der kan gøre dette job meget enklere.

I denne korte vejledning ser vi på brugerdefinerede Jackson-serier og viser hvordan man får adgang til standardserialisatorer inde i en tilpasset serializer.

2. Prøvedatamodel

Før vi dykker ned i tilpasningen af ​​Jackson, lad os se på vores prøve Folder klasse, som vi ønsker at serieisere:

offentlig klasse Mappe {privat Lang id; privat strengnavn; privat String ejer; privat Dato oprettet; privat Dato ændret; privat Dato lastAccess; private List-filer = ny ArrayList (); // standard getters og setter} 

Og Fil klasse, der er defineret som en Liste inde i vores Folder klasse:

offentlig klasse Fil {privat Lang id; privat strengnavn; // standard getters og setter} 

3. Custom Serializers i Jackson

Den største fordel ved at bruge brugerdefinerede serialiserere er, at vi ikke behøver at ændre vores klassestruktur. Plus, vi kan let afkoble vores forventede adfærd fra selve klassen.

Så lad os forestille os, at vi ønsker et reduceret syn på vores Folder klasse:

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

Som vi vil se i de næste sektioner, er der flere måder, hvorpå vi kan opnå vores ønskede output i Jackson.

3.1. Brute Force-tilgang

For det første uden at bruge Jacksons standardserialiserere kan vi oprette en brugerdefineret serializer, hvor vi selv gør alt det tunge.

Lad os oprette en tilpasset serializer til vores Folder klasse for at opnå dette:

public class FolderJsonSerializer udvider StdSerializer {public FolderJsonSerializer () {super (Folder.class); } @Override public void serialize (Folder value, JsonGenerator gen, SerializerProvider provider) kaster IOException {gen.writeStartObject (); gen.writeStringField ("navn", værdi.getnavn ()); gen.writeArrayFieldStart ("filer"); for (Filfil: value.getFiles ()) {gen.writeStartObject (); gen.writeNumberField ("id", file.getId ()); gen.writeStringField ("navn", fil.getnavn ()); gen.writeEndObject (); } gen.writeEndArray (); gen.writeEndObject (); }}

Således kan vi serieisere vores Folder klasse til en reduceret visning, der kun indeholder de felter, vi ønsker.

3.2. Brug internt ObjectMapper

Selvom tilpassede serialiserere giver os fleksibiliteten til at ændre hver ejendom i detaljer, kan vi gøre vores job lettere ved genbrug af Jacksons standardserialiserere.

En måde at bruge standard serialiseringsapparaterne er at få adgang til det interne ObjectMapper klasse:

@Override public void serialize (Folder value, JsonGenerator gen, SerializerProvider provider) kaster IOException {gen.writeStartObject (); gen.writeStringField ("navn", værdi.getnavn ()); ObjectMapper-kortlægger = (ObjectMapper) gen.getCodec (); gen.writeFieldName ("filer"); String stringValue = mapper.writeValueAsString (value.getFiles ()); gen.writeRawValue (stringValue); gen.writeEndObject (); } 

Så Jackson håndterer simpelthen de tunge løft ved at serieisere Liste af Fil objekter, og så vil vores output være den samme.

3.3. Ved brug af SerializerProvider

En anden måde at kalde standard-serialisatorerne på er at bruge SerializerProvider. Derfor delegerer vi processen til standardserier af typen Fil.

Lad os nu forenkle vores kode lidt ved hjælp af SerializerProvider:

@Override public void serialize (Folder value, JsonGenerator gen, SerializerProvider provider) kaster IOException {gen.writeStartObject (); gen.writeStringField ("navn", værdi.getnavn ()); provider.defaultSerializeField ("filer", value.getFiles (), gen); gen.writeEndObject (); } 

Og ligesom før får vi den samme produktion.

4. Et muligt rekursionsproblem

Afhængigt af anvendelsestilfælde skal vi muligvis udvide vores serielle data ved at inkludere flere detaljer for Folder. Dette kan være til et ældre system eller en ekstern applikation, der skal integreres, som vi ikke har en chance for at ændre.

Lad os ændre vores serializer for at oprette en detaljer felt for vores serielle data for blot at eksponere alle felterne i Folder klasse:

@Override public void serialize (Folder value, JsonGenerator gen, SerializerProvider provider) kaster IOException {gen.writeStartObject (); gen.writeStringField ("navn", værdi.getnavn ()); provider.defaultSerializeField ("filer", value.getFiles (), gen); // denne linje forårsager undtagelsesleverandør.defaultSerializeField ("detaljer", værdi, gen); gen.writeEndObject (); } 

Denne gang får vi en StackOverflowError undtagelse.

Når vi definerer en brugerdefineret serializer, tilsidesætter Jackson originalen internt BeanSerializer eksempel der oprettes til typen Folder. Derfor er vores SerializerProvider finder den tilpassede serializer hver gang i stedet for standard, og dette forårsager en uendelig løkke.

Så hvordan løser vi dette problem? Vi ser en brugbar løsning til dette scenario i det næste afsnit.

5. Brug BeanSerializerModifier

En mulig løsning bruger BeanSerializerModifierfor at gemme standard serialiseringen for typen Folderinden Jackson internt tilsidesætter det.

Lad os ændre vores serializer og tilføje et ekstra felt - defaultSerializer:

privat endelig JsonSerializer defaultSerializer; offentlig FolderJsonSerializer (JsonSerializer defaultSerializer) {super (Folder.class); this.defaultSerializer = defaultSerializer; } 

Dernæst opretter vi en implementering af BeanSerializerModifier at videregive standardserialiseringen

public class FolderBeanSerializerModifier udvider BeanSerializerModifier {@Override public JsonSerializer modifySerializer (SerializationConfig config, BeanDescription beanDesc, JsonSerializer serializer) {if (beanDesc.getBeanClass (). equals (Foldererial)) } returner serializer; }} 

Nu skal vi registrere vores BeanSerializerModifier som et modul til at få det til at fungere:

ObjectMapper-kortlægger = ny ObjectMapper (); SimpleModule-modul = nyt SimpleModule (); module.setSerializerModifier (ny FolderBeanSerializerModifier ()); mapper.registerModule (modul); 

Derefter bruger vi defaultSerializer til detaljer Mark:

@Override public void serialize (Folder value, JsonGenerator gen, SerializerProvider provider) kaster IOException {gen.writeStartObject (); gen.writeStringField ("navn", værdi.getnavn ()); provider.defaultSerializeField ("filer", value.getFiles (), gen); gen.writeFieldName ("detaljer"); defaultSerializer.serialize (værdi, gen, udbyder); gen.writeEndObject (); } 

Endelig vil vi måske fjerne filer felt fra detaljer da vi allerede skriver det separat i de serielle data.

Så vi ignorerer simpelthen filer felt i vores Folder klasse:

@JsonIgnorer private listefiler = ny ArrayList (); 

Endelig er problemet løst, og vi får også vores forventede output:

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

6. Konklusion

I denne vejledning vi lærte, hvordan man kalder standardserialisatorer inde i en tilpasset serializer i Jackson Library.

Som altid er alle kodeeksemplerne i denne vejledning tilgængelige på GitHub.


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