Ekskluder felt fra serialisering i Gson

1. Oversikt

I denne korte opplæringen skal vi utforske de tilgjengelige alternativene for å ekskludere ett eller flere felt i en Java-klasse og dens underklasser fra Gson-serialisering.

2. Første oppsett

La oss først definere klassene våre:

@Data @AllArgsConstructor offentlig klasse MyClass {privat lang id; privat strengnavn; private String andre; privat MySubClass-underklasse; } @ Data @ AllArgsConstructor offentlig klasse MySubClass {privat lang id; privat strengbeskrivelse; private String andreVerboseInfo; } 

Vi har kommentert dem med Lombok for enkelhets skyld (syntaktisk sukker for getters, settere, konstruktører ...).

La oss nå fylle dem:

MySubClass subclass = new MySubClass (42L, "the answer", "Verbose field not to serialize") MyClass source = new MyClass (1L, "foo", "bar", subclass); 

Målet vårt er å forhindre MyClass.other og MySubClass.otherVerboseInfo felt fra å bli seriellisert.

Produksjonen vi forventer å få er:

{"id": 1, "name": "foo", "subclass": {"id": 42, "description": "the answer"}} 

I Java:

Streng forventet resultat = "{\" id \ ": 1, \" navn \ ": \" foo \ ", \" underklasse \ ": {\" id \ ": 42, \" beskrivelse \ ": \" svaret \ "}}"; 

3. Transient Modifier

Vi kan markere et felt med flyktig modifikator:

offentlig klasse MyClass {privat lang id; privat strengnavn; privat forbigående String andre; privat MySubClass-underklasse; } offentlig klasse MySubClass {privat lang id; privat strengbeskrivelse; privat forbigående String andreVerboseInfo; } 

Gson serializer ignorerer hvert felt som er erklært forbigående:

String jsonString = ny Gson (). ToJson (kilde); assertEquals (expectResult, jsonString); 

Selv om dette er veldig raskt, kommer det også med en alvorlig ulempe: hvert serialiseringsverktøy vil ta forbigående hensyn, ikke bare Gson.

Transient er Java-måten å ekskludere fra serialisering, så blir vårt felt også filtrert ut av SerialiserbarSerialisering og av hvert biblioteksverktøy eller rammeverk som administrerer objektene våre

I tillegg har flyktig nøkkelord fungerer alltid både for serialisering og deserialisering, noe som kan være begrensende avhengig av brukssakene.

4. @Avdekke Kommentar

Gson com.google.gson.annotations @Avdekke kommentar fungerer omvendt.

Vi kan bruke den til å erklære hvilke felt vi skal serialisere, og ignorere de andre:

offentlig klasse MyClass {@Expose private long id; @Expose private String name; private String andre; @Expose privat MySubClass-underklasse; } offentlig klasse MySubClass {@Expose private long id; @Expose private strengbeskrivelse; private String andreVerboseInfo; } 

For dette trenger vi å instansiere Gson med en GsonBuilder:

Gson gson = ny GsonBuilder () .excludeFieldsWithoutExposeAnnotation () .create (); String jsonString = gson.toJson (kilde); assertEquals (expectResult, jsonString); 

Denne gangen kan vi kontrollere på feltnivå om filtreringen skal skje for serialisering, deserialisering eller begge deler (standard).

La oss se hvordan vi kan forebygge MyClass.other fra å bli seriell, men la den bli fylt ut under en deserialisering fra JSON:

@Expose (serialize = false, deserialize = true) privat String andre; 

Selv om dette er den enkleste måten Gson tilbyr, og det ikke påvirker andre biblioteker, kan det innebære redundans i koden. Hvis vi har en klasse med hundre felt, og vi bare vil ekskludere ett felt, trenger vi å skrive nittiannotering, som er for mye.

5. Ekskludering Strategi

En svært tilpassbar løsning er bruken av en com.google.gson.Ekskludering Strategi.

Det lar oss definere (eksternt eller med en Anonimous Inner Class) en strategi for å instruere GsonBuilder om vi skal serieisere felt (og / eller klasser) med tilpassede kriterier.

Gson gson = ny GsonBuilder () .addSerializationExclusionStrategy (strategi) .create (); String jsonString = gson.toJson (kilde); assertEquals (expectResult, jsonString); 

La oss se noen eksempler på smarte strategier å bruke.

5.1. Med klasser og feltnavn

Selvfølgelig kan vi også kode et eller flere felt / klassenavn:

ExclusionStrategy strategy = new ExclusionStrategy () {@Override public boolean shouldSkipField (FieldAttributes field) {if (field.getDeclaringClass () == MyClass.class && field.getName (). Equals ("other")) {return true; } hvis (field.getDeclaringClass () == MySubClass.class && field.getName (). tilsvarer ("otherVerboseInfo")) {return true; } returner falsk; } @ Override public boolean shouldSkipClass (Class clazz) {return false; }}; 

Dette er raskt og rett til poenget, men ikke veldig gjenbrukbart og også utsatt for feil i tilfelle vi omdøper attributtene våre.

5.2. Med forretningskriterier

Siden vi bare må returnere en boolsk, kan vi implementere hver forretningslogikk vi liker i den metoden.

I det følgende eksemplet vil vi identifisere hvert felt som begynner med “annet” som felt som ikke skal serialiseres, uansett hvilken klasse de tilhører:

ExclusionStrategy-strategi = ny ExclusionStrategy () {@ Override public boolean shouldSkipClass (Class clazz) {return false; } @ Override public boolean shouldSkipField (FieldAttributes field) {return field.getName (). StartsWith ("other"); }}; 

5.3. Med en tilpasset kommentar

En annen smart tilnærming er å lage en tilpasset kommentar:

@Retention (RetentionPolicy.RUNTIME) @Target (ElementType.FIELD) public @interface Exclude {} 

Vi kan da utnytte Ekskludering Strategi for å få det til å fungere akkurat som med @Avdekke kommentar, men omvendt:

offentlig klasse MyClass {privat lang id; privat strengnavn; @ Ekskluder privat streng andre; privat MySubClass-underklasse; } offentlig klasse MySubClass {privat lang id; privat strengbeskrivelse; @Exclude private String otherVerboseInfo; } 

Og her er strategien:

ExclusionStrategy-strategi = ny ExclusionStrategy () {@ Override public boolean shouldSkipClass (Class clazz) {return false; } @ Override public boolean shouldSkipField (FieldAttributes field) {return field.getAnnotation (Exclude.class)! = Null; }}; 

Dette StackOverflow-svaret beskrev først og fremst denne teknikken.

Det tillater oss å skrive kommentaren og strategien en gang, og å kommentere feltene våre dynamisk uten ytterligere modifisering.

5.4. Utvid ekskluderingsstrategi til deserialisering

Uansett hvilken strategi vi bruker, kan vi alltid kontrollere hvor den skal brukes.

Bare under serialisering:

Gson gson = ny GsonBuilder (). AddSerializationExclusionStrategy (strategi) 

Bare under deserialisering:

Gson gson = ny GsonBuilder (). AddDeserializationExclusionStrategy (strategi) 

Alltid:

Gson gson = ny GsonBuilder (). SetExclusionStrategies (strategi); 

6. Konklusjon

Vi har sett forskjellige måter å ekskludere felt fra en klasse og dens underklasser under Gson-serialisering.

Vi har også utforsket de viktigste fordelene og fallgruvene ved hver løsning.

Som alltid er hele kildekoden tilgjengelig på Github.