Jackson vs Gson

1. Introduksjon

I denne artikkelen vil vi sammenligne Gson og Jackson APIer for serialisering og deserialisering av JSON-data til Java-objekter og omvendt.

Gson og Jackson er komplette biblioteker som tilbyr JSON databindende støtte for Java. Hver er aktivt utviklede open source-prosjekter som tilbyr håndtering av komplekse datatyper og støtte for Java Generics.

Og i de fleste tilfeller kan begge biblioteker deserialisere seg til en enhet uten å endre en enhetsklasse, noe som er viktig i tilfeller der en utvikler ikke har tilgang til enhetens kildekode.

2. Gson Maven avhengighet

 com.google.code.gson gson $ {gson.version} 

Du kan få den nyeste versjonen av Gson her.

3. Gson-serialisering

Serialisering konverterer Java-objekter til JSON-utgang. Tenk på følgende enheter:

offentlig klasse ActorGson {privat streng imdbId; privat Dato datoFødsel; privat Filmografi; // getters and setters, default constructor and field constructor utelatt} public class Movie {private String imdbId; privat streng direktør; private aktører på listen; // getters and setters, default constructor and field constructor utelatt}

3.1. Enkel serialisering

La oss starte med et eksempel på Java til JSON-serialisering:

SimpleDateFormat sdf = ny SimpleDateFormat ("dd-MM-åååå"); ActorGson rudyYoungblood = ny ActorGson ("nm2199632", sdf.parse ("21-09-1982"), Arrays.asList ("Apocalypto", "Beatdown", "Wind Walkers")); Filmfilm = ny film ("tt0472043", "Mel Gibson", Arrays.asList (rudyYoungblood)); String serializedMovie = nye Gson (). ToJson (film);

Dette vil føre til:

{"imdbId": "tt0472043", "regissør": "Mel Gibson", "skuespillere": [{"imdbId": "nm2199632", "dateOfBirth": "21. september 1982 12:00:00", " filmografi ": [" Apocalypto "," Beatdown "," Wind Walkers "]}}}

Som standard:

  • Alle eiendommer er seriell fordi de ikke har noe null verdier
  • fødselsdato feltet ble oversatt med standard Gson-datomønster
  • Utdata er ikke formatert, og JSON-eiendomsnavn tilsvarer Java-enhetene

3.2. Egendefinert serialisering

Ved å bruke en tilpasset serializer kan vi endre standard oppførsel. Vi kan introdusere et outputformater med HTML, håndtak null verdier, ekskluder egenskaper fra utdata, eller legg til en ny utgang.

ActorGsonSerializer endrer generering av JSON-kode for ActorGson element:

offentlig klasse ActorGsonSerializer implementerer JsonSerializer {private SimpleDateFormat sdf = nye SimpleDateFormat ("dd-MM-åååå"); @Override public JsonElement serialize (ActorGson actor, Type type, JsonSerializationContext jsonSerializationContext) {JsonObject actorJsonObj = new JsonObject (); actorJsonObj.addProperty ("IMDB-kode", actor.getImdbId ()); actorJsonObj.addProperty ("Fødselsdato", actor.getDateOfBirth ()! = null? sdf.format (actor.getDateOfBirth ()): null); actorJsonObj.addProperty ("N ° Film: ", actor.getFilmography ()! = null? actor.getFilmography (). size (): null); actorJsonObj.addProperty (" filmography ", actor.getFilmography ()! = null? convertFilmography (actor.getFilmography ()): null); return skuespillerJsonObj;} privat String convertFilmography (List filmography) {return filmography.stream () .collect (Collectors.joining ("-"));}}

For å ekskludere regissør eiendom, den @Avdekke kommentar brukes for eiendommer vi vil vurdere:

offentlig klasse MovieWithNullValue {@Expose private String imdbId; privat String direktør; @Expose private List skuespillere; }

Nå kan vi fortsette med Gson-objektoppretting ved hjelp av GsonBuilder klasse:

Gson gson = ny GsonBuilder () .setPrettyPrinting () .excludeFieldsWithoutExposeAnnotation () .serializeNulls () .disableHtmlEscaping () .registerTypeAdapter (ActorGson.class, new ActorGsonSerializer ()) .create () SimpleDateFormat sdf = ny SimpleDateFormat ("dd-MM-åååå"); ActorGson rudyYoungblood = ny ActorGson ("nm2199632", sdf.parse ("21-09-1982"), Arrays.asList ("Apocalypto", "Beatdown", "Wind Walkers")); MovieWithNullValue movieWithNullValue = ny MovieWithNullValue (null, "Mel Gibson", Arrays.asList (rudyYoungblood)); String serializedMovie = gson.toJson (movieWithNullValue);

Resultatet er følgende:

{"imdbId": null, "actor": [{"IMDB-kode":" nm2199632 ","Fødselsdato": "21-09-1982", "N ° Film: ": 3," filmography ":" Apocalypto-Beatdown-Wind Walkers "}]}

Legg merke til det:

  • utdataene er formatert
  • noen eiendomsnavn endres og inneholder HTML
  • null verdier er inkludert, og regissør feltet er utelatt
  • Dato er nå i dd-MM-åååå format
  • en ny eiendom er til stede - N ° Film
  • filmografi er en formatert eiendom, ikke standard JSON-listen

4. Gson-deserialisering

4.1. Enkel deserialisering

Deserialisering konverterer JSON-inngang til Java-objekter. For å illustrere resultatet implementerer vi toString () metode i begge enhetsklasser:

public class Movie {@Override public String toString () {return "Film [imdbId =" + imdbId + ", regissør =" + regissør + ", skuespillere =" + skuespillere + "]"; } ...} offentlig klasse ActorGson {@Override public String toString () {return "ActorGson [imdbId =" + imdbId + ", dateOfBirth =" + dateOfBirth + ", filmografi =" + filmografi + "]"; } ...}

Deretter bruker vi seriell JSON og kjører den gjennom standard Gson-deserialisering:

Streng jsonInput = "{\" imdbId \ ": \" tt0472043 \ ", \" skuespillere \ ":" + "[{\" imdbId \ ": \" nm2199632 \ ", \" dateOfBirth \ ": \" 1982- 09-21T12: 00: 00 + 01: 00 \ "," + "\" filmografi \ ": [\" Apocalypto \ ", \" Beatdown \ ", \" Wind Walkers \ "]}]}"; Film outputMovie = ny Gson (). Fra Json (jsonInput, Movie.class); outputMovie.toString ();

Resultatet er oss enhetene, fylt med dataene fra JSON-inngangen:

Film [imdbId = tt0472043, regissør = null, skuespillere = [ActorGson [imdbId = nm2199632, dateOfBirth = Tirsdag 21. september 04:00:00 PDT 1982, filmografi = [Apocalypto, Beatdown, Wind Walkers]]]]

Som det var tilfellet med den enkle serien:

  • JSON-inngangsnavnene må samsvare med Java-enhetsnavnene, ellers er de satt til null.
  • fødselsdato feltet ble oversatt med standard Gson-datomønster, ignorert tidssonen.

4.2. Tilpasset deserialisering

Ved å bruke en egendefinert deserializer kan vi endre standard deserializer-atferd. I dette tilfellet vil vi at datoen skal gjenspeile riktig tidssone for fødselsdato. Vi bruker en skikk ActorGsonDeserializerActorGson enhet for å oppnå dette:

offentlig klasse ActorGsonDeserializer implementerer JsonDeserializer {private SimpleDateFormat sdf = nye SimpleDateFormat ("åååå-MM-dd'T'HH: mm: ss"); @Override public ActorGson deserialize (JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) kaster JsonParseException {JsonObject jsonObject = json.getAsJsonObject (); JsonElement jsonImdbId = jsonObject.get ("imdbId"); JsonElement jsonDateOfBirth = jsonObject.get ("dateOfBirth"); JsonArray jsonFilmography = jsonObject.getAsJsonArray ("filmografi"); ArrayList filmList = ny ArrayList (); hvis (jsonFilmography! = null) {for (int i = 0; i <jsonFilmography.size (); i ++) {filmList.add (jsonFilmography.get (i) .getAsString ()); }} ActorGson actorGson = ny ActorGson (jsonImdbId.getAsString (), sdf.parse (jsonDateOfBirth.getAsString ()), filmList); retur skuespillerGson; }}

Vi ansatt a SimpleDateFormat parser for å analysere inngangsdatoen, og tar hensyn til tidssonen.

Merk at vi kunne ha bestemt oss for å bare skrive en tilpasset deserializer for bare datoen, men den ActorGsonDeserializer gir en mer detaljert oversikt over deserialiseringsprosessen.

Vær også oppmerksom på at Gson-tilnærmingen ikke krever endring av ActorGson enhet, som er ideell ettersom vi kanskje ikke alltid har tilgang til inngangsenheten. Vi bruker den tilpassede deserializer her:

Streng jsonInput = "{\" imdbId \ ": \" tt0472043 \ ", \" skuespillere \ ":" + "[{\" imdbId \ ": \" nm2199632 \ ", \" dateOfBirth \ ": \" 1982- 09-21T12: 00: 00 + 01: 00 \ ", + \" filmografi \ ": [\" Apocalypto \ ", \" Beatdown \ ", \" Wind Walkers \ "]}]}"; Gson gson = ny GsonBuilder () .registerTypeAdapter (ActorGson.class, ny ActorGsonDeserializer ()) .create (); Film outputMovie = gson.fromJson (jsonInput, Movie.class); outputMovie.toString ();

Resultatet ligner på det enkle deserialiseringsresultatet, bortsett fra at datoen bruker riktig tidssone:

Film [imdbId = tt0472043, regissør = null, skuespillere = [ActorGson [imdbId = nm2199632, dateOfBirth = Tirsdag 21. september 12:00:00 PDT 1982, filmografi = [Apocalypto, Beatdown, Wind Walkers]]]]

5. Jackson Maven Avhengighet

 com.fasterxml.jackson.core jackson-databind $ {jackson.version} 

Du kan få den nyeste versjonen av Jackson her.

6. Jackson Serialization

6.1. Enkel serialisering

Her vil vi bruke Jackson til å skaffe det samme serieinnholdet vi hadde med Gson ved hjelp av følgende enheter. Merk at enhetens getters / setters må være offentlige:

offentlig klasse ActorJackson {private String imdbId; privat Dato datoFødsel; privat Listografi; // påkrevde getters og settere, standardkonstruktør // og feltkonstruktørdetaljer utelatt} public class Movie {private String imdbId; privat String direktør; private aktører på listen; // nødvendige getters og settere, standardkonstruktør // og feltkonstruktørdetaljer utelatt} SimpleDateFormat sdf = ny SimpleDateFormat ("dd-MM-åååå"); ActorJackson rudyYoungblood = ny ActorJackson ("nm2199632", sdf.parse ("21-09-1982"), Arrays.asList ("Apocalypto", "Beatdown", "Wind Walkers")); Filmfilm = ny film ("tt0472043", "Mel Gibson", Arrays.asList (rudyYoungblood)); ObjectMapper mapper = ny ObjectMapper (); String jsonResult = mapper.writeValueAsString (film);

Resultatet er som følger:

{"imdbId": "tt0472043", "regissør": "Mel Gibson", "skuespillere": [{"imdbId": "nm2199632", "dateOfBirth": 401439600000, "filmography": ["Apocalypto", "Beatdown" , "Wind Walkers"]}]}

Noen interessante notater:

  • ObjectMapper er vår Jackson serializer / deserializer
  • Utgangen JSON er ikke formatert
  • Som standard er Java Date oversatt til lang verdi

6.2. Egendefinert serialisering

Vi kan lage en Jackson serializer for Skuespiller Jackson elementgenerering ved å utvide StdSerializer for vår enhet. Vær igjen oppmerksom på at entitetsoppsetterne / setterne må være offentlige:

offentlig klasse ActorJacksonSerializer utvider StdSerializer {private SimpleDateFormat sdf = nye SimpleDateFormat ("dd-MM-åååå"); offentlig ActorJacksonSerializer (klasse t) {super (t); } @ Override public void serialize (ActorJackson actor, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) kaster IOException {jsonGenerator.writeStartObject (); jsonGenerator.writeStringField ("imdbId", actor.getImdbId ()); jsonGenerator.writeObjectField ("dateOfBirth", actor.getDateOfBirth ()! = null? sdf.format (actor.getDateOfBirth ()): null); jsonGenerator.writeNumberField ("N ° Film:", actor.getFilmography ()! = null? actor.getFilmography (). størrelse (): null); jsonGenerator.writeStringField ("filmography", actor.getFilmography () .stream (). collect (Collectors.joining ("-"))); jsonGenerator.writeEndObject (); }}

Vi oppretter en filmenhet for å tillate ignorering av regissør felt:

offentlig klasse MovieWithNullValue {privat streng imdbId; @JsonIgnorer privat strengdirektør; private aktører på listen; // nødvendige getters og setters, standardkonstruktør // og feltkonstruktørdetaljer utelatt}

Nå kan vi fortsette med en skikk ObjectMapper opprettelse og oppsett:

SimpleDateFormat sdf = ny SimpleDateFormat ("dd-MM-åååå"); ActorJackson rudyYoungblood = ny ActorJackson ("nm2199632", sdf.parse ("21-09-1982"), Arrays.asList ("Apocalypto", "Beatdown", "Wind Walkers")); MovieWithNullValue movieWithNullValue = ny MovieWithNullValue (null, "Mel Gibson", Arrays.asList (rudyYoungblood)); SimpleModule-modul = ny SimpleModule (); module.addSerializer (ny ActorJacksonSerializer (ActorJackson.class)); ObjectMapper mapper = ny ObjectMapper (); String jsonResult = mapper.registerModule (module) .writer (new DefaultPrettyPrinter ()) .writeValueAsString (movieWithNullValue);

Utgangen er formatert JSON som håndterer null verdier, formaterer datoen, ekskluderer regissør felt og viser ny utdata fra Nr:

{"skuespillere": [{"imdbId": "nm2199632", "dateOfBirth": "21-09-1982", "N ° Film:": 3, "filmography": "Apocalypto-Beatdown-Wind Walkers"}] , "imdbID": null}

7. Jackson deserialisering

7.1. Enkel deserialisering

For å illustrere resultatet implementerer vi toString () metode i begge Jackson-enhetsklassene:

offentlig klassefilm {@Override public String toString () {return "Film [imdbId =" + imdbId + ", regissør =" + regissør + ", skuespillere =" + skuespillere + "]"; } ...} offentlig klasse ActorJackson {@Override public String toString () {return "ActorJackson [imdbId =" + imdbId + ", dateOfBirth =" + dateOfBirth + ", filmografi =" + filmografi + "]"; } ...}

Deretter bruker vi den serielle JSON og kjører den gjennom Jackson deserialisering:

Streng jsonInput = "{\" imdbId \ ": \" tt0472043 \ ", \" skuespillere \ ": [{\" imdbId \ ": \" nm2199632 \ ", \" dateOfBirth \ ": \" 1982-09-21T12 : 00: 00 + 01: 00 \ ", \" filmografi \ ": [\" Apocalypto \ ", \" Beatdown \ ", \" Wind Walkers \ "]}]}"; ObjectMapper mapper = ny ObjectMapper (); Filmfilm = mapper.readValue (jsonInput, Movie.class);

Resultatet er oss enhetene, fylt med dataene fra JSON-inngangen:

Film [imdbId = tt0472043, regissør = null, skuespillere = [ActorJackson [imdbId = nm2199632, dateOfBirth = Tirsdag 21. september 04:00:00 PDT 1982, filmografi = [Apocalypto, Beatdown, Wind Walkers]]]]

Som det var tilfelle med den enkle serien:

  • JSON-inngangsnavnene må svare til Java-enhetsnavnene, ellers er de satt til null,
  • fødselsdato feltet ble oversatt med standard Jackson-datomønster, ignorert tidssonen.

7.2. Tilpasset deserialisering

Ved å bruke en egendefinert deserializer kan vi endre standard deserializer-atferd.

I dette tilfellet vil vi at datoen skal gjenspeile riktig tidssone for fødselsdato, så vi legger til en DateFormatter til Jackson ObjectMapper:

Streng jsonInput = "{\" imdbId \ ": \" tt0472043 \ ", \" regissør \ ": \" Mel Gibson \ ", \" skuespillere \ ": [{\" imdbId \ ": \" nm2199632 \ ", \ "dateOfBirth \": \ "1982-09-21T12: 00: 00 + 01: 00 \", \ "filmografi \": [\ "Apocalypto \", \ "Beatdown \", \ "Wind Walkers \"] }]} "; ObjectMapper mapper = ny ObjectMapper (); DateFormat df = new SimpleDateFormat ("åååå-MM-dd'T'HH: mm: ss"); mapper.setDateFormat (df); Filmfilm = mapper.readValue (jsonInput, Movie.class); movie.toString ();

Resultatet gjenspeiler riktig tidssone med datoen:

Film [imdbId = tt0472043, regissør = Mel Gibson, skuespillere = [ActorJackson [imdbId = nm2199632, dateOfBirth = Tirsdag 21. september 12:00:00 PDT 1982, filmografi = [Apocalypto, Beatdown, Wind Walkers]]]]

Denne løsningen er ren og enkel.

Alternativt kunne vi ha laget en tilpasset deserializer for Skuespiller Jackson klasse registrerte denne modulen hos vår ObjectMapper, og deserialiserte datoen ved hjelp av @JsonDeserialize kommentar på Skuespiller Jackson enhet.

Ulempen med denne tilnærmingen er behovet for å endre enheten, noe som kanskje ikke er ideelt i tilfeller der vi ikke har tilgang til inngangsenhetsklassene.

8. Konklusjon

Både Gson og Jackson er gode alternativer for serialisering / deserialisering av JSON-data, enkle å bruke og godt dokumentert.

Fordeler med Gson:

  • Enkelhet av toJson/fraJson i de enkle tilfellene
  • For deserialisering trenger du ikke tilgang til Java-enhetene

Fordeler med Jackson:

  • Innebygd i alle JAX-RS (Jersey, Apache CXF, RESTEasy, Restlet) og Spring framework
  • Omfattende kommentarstøtte

Du finner koden for Gson og Jackson på GitHub.


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