Ekskluder felter fra serialisering i Gson

1. Oversigt

I denne korte vejledning skal vi undersøge de tilgængelige muligheder for at ekskludere et eller flere felter i en Java-klasse og dens underklasser fra Gson-serialisering.

2. Første opsætning

Lad os først definere vores klasser:

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

Vi har kommenteret dem med Lombok for nemheds skyld (syntaktisk sukker til getters, settere, konstruktører ...).

Lad os nu udfylde dem:

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

Vores mål er at forhindre MyClass.other og MySubClass.otherVerboseInfo felter fra at blive serieliseret.

Det output, vi forventer at få, er:

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

I Java:

String expectResult = "{\" id \ ": 1, \" navn \ ": \" foo \ ", \" underklasse \ ": {\" id \ ": 42, \" beskrivelse \ ": \" svaret \ "}}"; 

3. Forbigående modifikator

Vi kan markere et felt med forbigående modifikator:

offentlig klasse MyClass {privat lang id; privat strengnavn; privat forbigående String andre; privat MySubClass-underklasse; } offentlig klasse MySubClass {privat lang id; privat streng beskrivelse; privat forbigående String andenVerboseInfo; } 

Gson serializer ignorerer hvert felt, der er erklæret forbigående:

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

Selvom dette er meget hurtigt, kommer det også med en alvorlig ulempe: hvert serialiseringsværktøj vil tage forbigående i betragtning, ikke kun Gson.

Forbigående er Java-metoden til at udelukke fra serialisering, så filtreres vores felt også af Serialiserbar'S serialisering og af ethvert biblioteksværktøj eller ramme, der styrer vores objekter.

Derudover er forbigående nøgleord fungerer altid både til serialisering og deserialisering, hvilket kan være begrænsende afhængigt af brugssagerne.

4. @Udsætte Kommentar

Gson com.google.gson.annotations @Udsætte kommentar fungerer omvendt.

Vi kan bruge den til at erklære, hvilke felter der skal serieiseres, og ignorere de andre:

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

Til dette er vi nødt til at instantiere Gson med en GsonBuilder:

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

Denne gang kan vi kontrollere på feltniveau, om filtreringen skal ske til serialisering, deserialisering eller begge dele (standard).

Lad os se, hvordan man forhindrer det MyClass.other fra at blive serialiseret, men tillade at den udfyldes under en deserialisering fra JSON:

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

Selvom dette er den nemmeste måde, som Gson leverer, og det ikke påvirker andre biblioteker, kan det antyde redundans i koden. Hvis vi har en klasse med hundrede felter, og vi kun vil udelukke et felt, er vi nødt til at skrive enoghalvfems annotering, som er overdreven.

5. Udelukkelse Strategi

En meget tilpasselig løsning er brugen af ​​en com.google.gson.Udelukkelse Strategi.

Det giver os mulighed for at definere (eksternt eller med en anonim indre klasse) en strategi til at instruere GsonBuilder om, hvorvidt felter (og / eller klasser) skal serialiseres med tilpassede kriterier.

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

Lad os se nogle eksempler på smarte strategier at bruge.

5.1. Med klasser og feltnavne

Selvfølgelig kan vi også hardkode et eller flere navne på felter / klasser:

ExclusionStrategy-strategi = ny 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 (). er lig med ("otherVerboseInfo")) {return true; } returner falsk; } @ Override public boolean shouldSkipClass (Class clazz) {return false; }}; 

Dette er hurtigt og lige til det punkt, men ikke særlig genanvendeligt og også tilbøjeligt til fejl, hvis vi omdøber vores attributter.

5.2. Med forretningskriterier

Da vi simpelthen skal returnere en boolsk, kan vi implementere enhver forretningslogik, vi kan lide inden for den metode.

I det følgende eksempel identificerer vi hvert felt, der starter med "andet", som felter, der ikke skal serialiseres, uanset 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 brugerdefineret kommentar

En anden smart tilgang er at oprette en brugerdefineret kommentar:

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

Vi kan derefter udnytte Udelukkelse Strategi for at få det til at fungere nøjagtigt som med @Udsætte kommentar, men omvendt:

offentlig klasse MyClass {privat lang id; privat strengnavn; @Exclude private String andre; privat MySubClass-underklasse; } offentlig klasse MySubClass {privat lang id; privat streng beskrivelse; @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-svar beskrev først og fremmest denne teknik.

Det giver os mulighed for at skrive kommentaren og strategien en gang og dynamisk kommentere vores felter uden yderligere ændringer.

5.4. Udvid ekskluderingsstrategi til deserialisering

Uanset hvilken strategi vi bruger, kan vi altid kontrollere, hvor den skal anvendes.

Kun under serialisering:

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

Kun under deserialisering:

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

Altid:

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

6. Konklusion

Vi har set forskellige måder at ekskludere felter fra en klasse og dens underklasser under Gson-serialisering.

Vi har også undersøgt de største fordele og faldgruber ved enhver løsning.

Som altid er den fulde kildekode tilgængelig på Github.