Jackson tegen Gson

1. Inleiding

In dit artikel vergelijken we de API's van Gson en Jackson voor het serialiseren en deserialiseren van JSON-gegevens naar Java-objecten en vice versa.

Gson en Jackson zijn complete bibliotheken die ondersteuning bieden voor JSON-gegevensbinding voor Java. Het zijn stuk voor stuk actief ontwikkelde open-sourceprojecten die complexe gegevenstypen en ondersteuning voor Java Generics bieden.

En in de meeste gevallen kunnen beide bibliotheken deserialiseren naar een entiteit zonder een entiteitsklasse te wijzigen, wat belangrijk is in gevallen waarin een ontwikkelaar geen toegang heeft tot de broncode van de entiteit.

2. Afhankelijkheid van Gson Maven

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

U kunt de nieuwste versie van Gson hier downloaden.

3. Gson-serialisering

Serialisatie converteert Java-objecten naar JSON-uitvoer. Beschouw de volgende entiteiten:

openbare klasse ActorGson {privé String imdbId; privé date dateOfBirth; privélijst filmografie; // getters en setters, standaard constructor en field constructor weggelaten} public class Movie {private String imdbId; privé String-regisseur; privélijst actoren; // getters en setters, standaard constructor en field constructor weggelaten}

3.1. Eenvoudige serialisering

Laten we beginnen met een voorbeeld van serialisering van Java naar JSON:

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

Dit resulteert in:

{"imdbId": "tt0472043", "director": "Mel Gibson", "actors": [{"imdbId": "nm2199632", "dateOfBirth": "21 september 1982 12:00:00", " filmografie ": [" Apocalypto "," Beatdown "," Wind Walkers "]}]}

Standaard:

  • Alle eigenschappen zijn geserialiseerd omdat ze geen nul waarden
  • geboortedatum veld is vertaald met het standaard Gson-datumpatroon
  • De uitvoer is niet opgemaakt en de JSON-eigenschapsnamen komen overeen met de Java-entiteiten

3.2. Aangepaste serialisering

Door een aangepaste serialisator te gebruiken, kunnen we het standaardgedrag aanpassen. We kunnen een uitvoerformatter introduceren met HTML, handle nul waarden, eigenschappen uitsluiten van uitvoer of een nieuwe uitvoer toevoegen.

ActeurGsonSerializer wijzigt het genereren van JSON-code voor het ActeurGson element:

openbare klasse ActorGsonSerializer implementeert JsonSerializer {private SimpleDateFormat sdf = nieuwe SimpleDateFormat ("dd-MM-jjjj"); @Override public JsonElement serialize (ActorGson-actor, Type type, JsonSerializationContext jsonSerializationContext) {JsonObject actorJsonObj = new JsonObject (); actorJsonObj.addProperty ("IMDB-code", actor.getImdbId ()); actorJsonObj.addProperty ("Geboortedatum", 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 actorJsonObj;} private String convertFilmography (List filmography) {return filmography.stream () .collect (Collectors.joining ("-"));}}

Om het regisseur eigenschap, de @Expose annotatie wordt gebruikt voor eigenschappen die we willen overwegen:

openbare klasse MovieWithNullValue {@Expose private String imdbId; privé String-regisseur; @Expose privélijst actoren; }

Nu kunnen we doorgaan met het maken van Gson-objecten met behulp van de GsonBuilder klasse:

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

Het resultaat is het volgende:

{"imdbId": null, "acteurs": [{"IMDB-code":" nm2199632 ","Geboortedatum": "21-09-1982", "N ° film: ": 3," filmography ":" Apocalypto-Beatdown-Wind Walkers "}]}

Let erop dat:

  • de uitvoer is geformatteerd
  • sommige eigenschapsnamen zijn gewijzigd en bevatten HTML
  • nul waarden zijn inbegrepen, en de regisseur veld is weggelaten
  • Datum is nu in de dd-MM-jjjj formaat
  • er is een nieuw pand aanwezig - N ° film
  • filmografie is een opgemaakte eigenschap, niet de standaard JSON-lijst

4. Gson-deserialisatie

4.1. Eenvoudige deserialisering

Deserialisatie zet JSON-invoer om in Java-objecten. Om de output te illustreren, implementeren we de toString () methode in beide entiteitsklassen:

public class Movie {@Override public String toString () {return "Movie [imdbId =" + imdbId + ", director =" + director + ", actors =" + acteurs + "]"; } ...} public class ActorGson {@Override public String toString () {return "ActorGson [imdbId =" + imdbId + ", dateOfBirth =" + dateOfBirth + ", filmography =" + filmography + "]"; } ...}

Vervolgens gebruiken we de geserialiseerde JSON en voeren deze standaard Gson-deserialisatie uit:

String jsonInput = "{\" imdbId \ ": \" tt0472043 \ ", \" acteurs \ ":" + "[{\" imdbId \ ": \" nm2199632 \ ", \" dateOfBirth \ ": \" 1982- 09-21T12: 00: 00 + 01: 00 \ "," + "\" filmografie \ ": [\" Apocalypto \ ", \" Beatdown \ ", \" Wind Walkers \ "]}]}"; Movie outputMovie = new Gson (). FromJson (jsonInput, Movie.class); outputMovie.toString ();

De uitvoer zijn wij onze entiteiten, gevuld met de gegevens van onze JSON-invoer:

Film [imdbId = tt0472043, director = null, acteurs = [ActorGson [imdbId = nm2199632, dateOfBirth = di 21 september 04:00:00 PDT 1982, filmografie = [Apocalypto, Beatdown, Wind Walkers]]]]

Zoals het geval was met de eenvoudige serialisator:

  • de JSON-invoernamen moeten overeenkomen met de Java-entiteitsnamen, of ze zijn ingesteld op null.
  • geboortedatum veld is vertaald met het standaard Gson-datumpatroon, waarbij de tijdzone wordt genegeerd.

4.2. Aangepaste deserialisering

Door een aangepaste deserialisator te gebruiken, kunnen we het standaardgedrag van de deserialisatie aanpassen. In dit geval willen we dat de datum de juiste tijdzone weergeeft geboortedatum. We gebruiken een op maat gemaakt ActorGsonDeserializer op de ActeurGson entiteit om dit te bereiken:

openbare klasse ActorGsonDeserializer implementeert JsonDeserializer {privé SimpleDateFormat sdf = nieuwe SimpleDateFormat ("jjjj-MM-dd'T'HH: mm: ss"); @Override public ActorGson deserialize (JsonElement json, Type type, JsonDeserializationContext jsonDeserializationContext) gooit JsonParseException {JsonObject jsonObject = json.getAsJsonObject (); JsonElement jsonImdbId = jsonObject.get ("imdbId"); JsonElement jsonDateOfBirth = jsonObject.get ("dateOfBirth"); JsonArray jsonFilmography = jsonObject.getAsJsonArray ("filmografie"); ArrayList filmList = nieuwe ArrayList (); if (jsonFilmography! = null) {voor (int i = 0; i <jsonFilmography.size (); i ++) {filmList.add (jsonFilmography.get (i) .getAsString ()); }} ActorGson actorGson = nieuwe ActorGson (jsonImdbId.getAsString (), sdf.parse (jsonDateOfBirth.getAsString ()), filmList); terugkeer actorGson; }}

We gebruikten een SimpleDateFormat parser om de invoerdatum te ontleden, rekening houdend met de tijdzone.

Merk op dat we hadden kunnen besluiten om gewoon een aangepaste deserializer te schrijven voor alleen de datum, maar de ActorGsonDeserializer biedt een meer gedetailleerd overzicht van het deserialisatieproces.

Merk ook op dat de Gson-benadering geen wijziging van het ActeurGson entiteit, wat ideaal is omdat we mogelijk niet altijd toegang hebben tot de invoerentiteit. We gebruiken hier de aangepaste deserializer:

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

De uitvoer is vergelijkbaar met het eenvoudige deserialisatie-resultaat, behalve dat de datum de juiste tijdzone gebruikt:

Film [imdbId = tt0472043, director = null, acteurs = [ActorGson [imdbId = nm2199632, dateOfBirth = di 21 september 12:00:00 PDT 1982, filmografie = [Apocalypto, Beatdown, Wind Walkers]]]]

5. Afhankelijkheid van Jackson Maven

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

Je kunt de nieuwste versie van Jackson hier downloaden.

6. Jackson-serialisering

6.1. Eenvoudige serialisering

Hier zullen we Jackson gebruiken om dezelfde geserialiseerde inhoud te verkrijgen die we hadden met Gson met behulp van de volgende entiteiten. Merk op dat de getters / setters van de entiteit openbaar moeten zijn:

openbare klasse ActorJackson {privé String imdbId; privé date dateOfBirth; privélijst filmografie; // vereiste getters en setters, standaard constructor // en veld constructor details weggelaten} public class Movie {private String imdbId; privé String-regisseur; privélijst actoren; // vereiste getters en setters, standaard constructor // en veld constructor details weggelaten} SimpleDateFormat sdf = nieuwe SimpleDateFormat ("dd-MM-jjjj"); ActorJackson rudyYoungblood = nieuwe ActorJackson ("nm2199632", sdf.parse ("21-09-1982"), Arrays.asList ("Apocalypto", "Beatdown", "Wind Walkers")); Movie movie = nieuwe film ("tt0472043", "Mel Gibson", Arrays.asList (rudyYoungblood)); ObjectMapper-mapper = nieuwe ObjectMapper (); String jsonResult = mapper.writeValueAsString (film);

De output is als volgt:

{"imdbId": "tt0472043", "director": "Mel Gibson", "actors": [{"imdbId": "nm2199632", "dateOfBirth": 401439600000, "filmography": ["Apocalypto", "Beatdown" , "Wind Walkers"]}]}

Enkele interessante opmerkingen:

  • ObjectMapper is onze Jackson serializer / deserializer
  • De output JSON is niet opgemaakt
  • Standaard wordt Java Date vertaald naar lang waarde

6.2. Aangepaste serialisering

We kunnen een Jackson-serialisator voor maken Acteur Jackson elementgeneratie door StdSerializer uit te breiden voor onze entiteit. Merk nogmaals op dat de entiteit getters / setters openbaar moet zijn:

openbare klasse ActorJacksonSerializer breidt StdSerializer {private SimpleDateFormat sdf = nieuwe SimpleDateFormat ("dd-MM-jjjj") uit; openbare ActorJacksonSerializer (Klasse t) {super (t); } @Override public void serialize (ActorJackson-acteur, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) gooit 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 (). size (): null); jsonGenerator.writeStringField ("filmografie", actor.getFilmography () .stream (). collect (Collectors.joining ("-"))); jsonGenerator.writeEndObject (); }}

We maken een film-entiteit om het negeren van de regisseur veld:

openbare klasse MovieWithNullValue {privé String imdbId; @JsonIgnore privé String-regisseur; privélijst actoren; // vereiste getters en setters, standaard constructor // en veld constructor details weggelaten}

Nu kunnen we doorgaan met een gewoonte ObjectMapper creatie en setup:

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

De uitvoer is geformatteerd JSON die afhandelt nul waarden, formatteert de datum, sluit de regisseur veld en toont nieuwe output van N °:

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

7. Jackson Deserialisatie

7.1. Eenvoudige deserialisering

Om de output te illustreren, implementeren we de toString () methode in beide Jackson-entiteitsklassen:

public class Movie {@Override public String toString () {return "Movie [imdbId =" + imdbId + ", director =" + director + ", actors =" + acteurs + "]"; } ...} public class ActorJackson {@Override public String toString () {return "ActorJackson [imdbId =" + imdbId + ", dateOfBirth =" + dateOfBirth + ", filmography =" + filmography + "]"; } ...}

Vervolgens gebruiken we de geserialiseerde JSON en voeren deze door Jackson-deserialisatie uit:

String jsonInput = "{\" imdbId \ ": \" tt0472043 \ ", \" acteurs \ ": [{\" imdbId \ ": \" nm2199632 \ ", \" dateOfBirth \ ": \" 1982-09-21T12 : 00: 00 + 01: 00 \ ", \" filmografie \ ": [\" Apocalypto \ ", \" Beatdown \ ", \" Wind Walkers \ "]}]}"; ObjectMapper-mapper = nieuwe ObjectMapper (); Movie movie = mapper.readValue (jsonInput, Movie.class);

De uitvoer zijn wij onze entiteiten, gevuld met de gegevens van onze JSON-invoer:

Film [imdbId = tt0472043, director = null, acteurs = [ActorJackson [imdbId = nm2199632, dateOfBirth = di 21 september 04:00:00 PDT 1982, filmografie = [Apocalypto, Beatdown, Wind Walkers]]]]

Zoals het geval was met de eenvoudige serialisator:

  • de JSON-invoernamen moeten overeenkomen met de Java-entiteitsnamen, of ze zijn ingesteld op nul,
  • geboortedatum veld is vertaald met het standaard Jackson-datumpatroon, waarbij de tijdzone wordt genegeerd.

7.2. Aangepaste deserialisering

Door een aangepaste deserialisator te gebruiken, kunnen we het standaardgedrag van de deserialisatie aanpassen.

In dit geval willen we dat de datum de juiste tijdzone weergeeft geboortedatum, dus voegen we een DateFormatter toe aan onze Jackson ObjectMapper:

String jsonInput = "{\" imdbId \ ": \" tt0472043 \ ", \" director \ ": \" Mel Gibson \ ", \" acteurs \ ": [{\" imdbId \ ": \" nm2199632 \ ", \ "dateOfBirth \": \ "1982-09-21T12: 00: 00 + 01: 00 \", \ "filmografie \": [\ "Apocalypto \", \ "Beatdown \", \ "Wind Walkers \"] }]} "; ObjectMapper-mapper = nieuwe ObjectMapper (); DateFormat df = nieuwe SimpleDateFormat ("jjjj-MM-dd'T'HH: mm: ss"); mapper.setDateFormat (df); Movie movie = mapper.readValue (jsonInput, Movie.class); movie.toString ();

De uitvoer geeft de juiste tijdzone weer met de datum:

Film [imdbId = tt0472043, regisseur = Mel Gibson, acteurs = [ActorJackson [imdbId = nm2199632, dateOfBirth = di 21 september 12:00:00 PDT 1982, filmografie = [Apocalypto, Beatdown, Wind Walkers]]]]

Deze oplossing is schoon en eenvoudig.

Als alternatief hadden we een aangepaste deserializer kunnen maken voor de Acteur Jackson class, heeft deze module geregistreerd bij onze ObjectMapper, en de datum gedeserialiseerd met behulp van de @JsonDeserialize annotatie op de Acteur Jackson entiteit.

Het nadeel van die benadering is de noodzaak om de entiteit te wijzigen, wat misschien niet ideaal is voor gevallen waarin we geen toegang hebben tot de invoerentiteitsklassen.

8. Conclusie

Zowel Gson als Jackson zijn goede opties voor het serialiseren / deserialiseren van JSON-gegevens, eenvoudig te gebruiken en goed gedocumenteerd.

Voordelen van Gson:

  • Eenvoud van naar Json/van Json in de eenvoudige gevallen
  • Voor deserialisatie heeft u geen toegang tot de Java-entiteiten nodig

Voordelen van Jackson:

  • Ingebouwd in alle JAX-RS- (Jersey, Apache CXF, RESTEasy, Restlet) en Spring-frameworks
  • Uitgebreide ondersteuning voor annotaties

Je kunt de code voor Gson en Jackson vinden op GitHub.