Jackson is een populaire bibliotheek voor het serialiseren/deserialiseren van Java-objecten naar verschillende tekstindelingen. De klasse ObjectMapper is de belangrijkste manier van de bibliotheek om met de JSON-indeling te werken. Voor andere formaten hebben we de afstammelingen ( XmlMapper , YAMLMapper ). Dankzij overerving kunnen we op een consistente manier met alle formaten werken, via één enkele interface.

Jar-bestanden downloaden

Voordat we de voorbeelden bestuderen, moeten we Jackson jar-bestanden downloaden en deze verbinden met het project in IntelliJ IDEA. Laten we het voorbeeld van jackson-databind nemen om te zien hoe u naar benodigde bestanden kunt zoeken:

  1. Ga naar de Maven Repository- website.

  2. Voer " jackson-databind " in het zoekvak in. Je krijgt het volgende:

  3. Het eerste zoekresultaat is waar we in geïnteresseerd zijn. Volg de link.

  4. Soms is een bepaalde versie van een bibliotheek vereist om compatibiliteit met andere componenten in een project te garanderen. De nieuwste versie zou moeten werken (op het moment van schrijven van deze les is dit 2.13.2.2). Volg de link.

  5. Op de pagina die wordt geopend, wilt u de link "bundel":

  6. Download het jar-bestand via deze link .

Door een vergelijkbare procedure te volgen, kunt u de rest van de benodigde jar-bestanden vinden en downloaden:

Nadat u alle benodigde bestanden hebt gedownload, verbindt u ze met het project in IntelliJ IDEA:

  1. Open de projectinstellingen (u kunt dit doen met de toetsencombinatie Ctrl+Alt+Shift+S ).

  2. Ga naar Bibliotheken .

  3. Druk op + en vervolgens op "Java". Selecteer alle gedownloade bestanden. Dit is waar we mee moeten eindigen:

  4. Dat is het einde van ons voorbereidende werk. Nu kunnen we ObjectMapper in actie uitproberen .

Serialisatie naar JSON

Laten we eerst een object serialiseren naar JSON:


import com.fasterxml.jackson.databind.ObjectMapper;
 
class Book {
	public String title;
	public String author;
	public int pages;
}
 
public class Solution {
	public static void main(String[] args) throws Exception {
    	Book book = new Book();
    	book.title = "Good Omens";
    	book.author = "Pratchett T., Gaiman N.";
    	book.pages = 383;
 
    	ObjectMapper mapper = new ObjectMapper();
    	String jsonBook = mapper.writeValueAsString(book);
    	System.out.println(jsonBook);
	}
}

Als u main uitvoert, krijgt u deze uitvoer:

{"title":"Goede voortekenen","author":"Pratchett T., Gaiman N.","pages":383}

De ObjectMapper heeft veel geavanceerde instellingen. Laten we er een gebruiken om de JSON-string leesbaarder te maken. Na het maken van deObjectMapperbezwaar, voer deze instructie uit:

mapper.enable(SerializationFeature.INDENT_OUTPUT);

De informatie in de uitvoer blijft hetzelfde, maar er zijn nu inspringingen en regeleinden:

{
  "title" : "Good Omens",
  "author" : "Pratchett T., Gaiman N.",
 "pages" : 383
}

Deserialisatie van JSON

Laten we nu de tegenovergestelde actie uitvoeren: we deserialiseren een string naar een object. Laten we, om te kunnen zien wat het programma doet, de methode toString in de klasse Book overschrijven :


@Override
public String toString() {
	return "Book{" +
        	"title='" + title + '\'' +
        	", author='" + author + '\'' +
        	", pages=" + pages +
        	'}';
}

En we zullen het volgende doen in de hoofdmethode :


public static void main(String[] args) throws Exception {
	String jsonString = "{\"title\":\"Good Omens\",\"author\":\"Pratchett T., Gaiman N.\",\"pages\":383}";
	Book book = new ObjectMapper().readValue(jsonString, Book.class);
	System.out.println(book);
}

Uitgang:

Boek{title='Good Omens', author='Pratchett T., Gaiman N.', pagina's=383}

De readValue- methode is overbelast — het heeft veel variaties die een bestand, een link, verschillende invoerstromen, enz. nodig hebben. Voor de eenvoud gebruikt ons voorbeeld een variant die een JSON-tekenreeks accepteert.

Zoals hierboven vermeld, heeft ObjectMapper veel instellingen. Laten we er een paar bekijken.

Onbekende eigenschappen negeren

Overweeg een situatie waarin een JSON-tekenreeks een eigenschap heeft die niet bestaat in de klasse Book :


public static void main(String[] args) throws Exception {
	String jsonString = """
        	{
          	"title" : "Good Omens",
          	"author" : "Pratchett T., Gaiman N.",
          	"pages" : 383,
          	"unknown property" : 42
        	}""";
	ObjectMapper mapper = new ObjectMapper();
	Book book = mapper.readValue(jsonString, Book.class);
	System.out.println(book);
}

Het uitvoeren van deze code geeft ons een UnrecognizedPropertyException . Dit is het standaardgedrag, maar we kunnen het wijzigen:


ObjectMapper mapper =
new ObjectMapper().configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Bij het maken van eenObjectMapperobject gebruiken we de configuratiemethode om de overeenkomstige instelling in te stellen op false . De configuratiemethode wijzigt het object waarop het is aangeroepen en retourneert vervolgens datzelfde object, dus we kunnen deze aanroep op een andere manier doen:


ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);

Qua functionaliteit is deze notatie net als de vorige.

Als we nu de hoofdmethode uitvoeren , zal de deserialisatie slagen en wordt de onbekende eigenschap genegeerd.

Handige annotaties

Jackson voorziet ons van verschillende annotaties waarmee we het serialisatieproces op allerlei manieren kunnen aanpassen. Laten we eens kijken naar enkele van de meest bruikbare:

@JsonIgnore — Deze annotatie wordt boven een element geplaatst dat moet worden genegeerd tijdens serialisatie/deserialisatie:


class Book {
	public String title;
	@JsonIgnore
	public String author;
	public int pages;
}

Hier deauteurveld wordt niet opgenomen in de resulterende JSON tijdens serialisatie. Na deserialisatie, deauteurveld krijgt de standaardwaarde (null), zelfs als de JSON een andere waarde had.

@JsonFormat — Met deze annotatie kunt u het formaat van de geserialiseerde gegevens instellen. Laten we nog een veld, een Date , toevoegen aan de klasse Book :


class Book {
	public String title;
	public String author;
	public int pages;
	public Date createdDate = new Date();
}

Na serialisatie krijgen we de volgende JSON:

 {
  "title" : "Good Omens",
  "author" : "Pratchett T., Gaiman N.",
  "pages" : 383,
  "createdDate" : 1649330880788
}

Zoals u kunt zien, werd de datum geserialiseerd als een nummer. We voegen een annotatie toe en stellen de indeling in:


class Book {
	public String title;
	public String author;
	public int pages;
	@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
	public Date createdDate = new Date();
}

Nu is het resultaat van serialisatie:

{
  "title" : "Good Omens",
  "author" : "Pratchett T., Gaiman N.",
  "pages" : 383,
  "createdDate" : "2022-04-07"
}

@JsonProperty — Met deze annotatie kunt u de naam wijzigen van de eigenschap die het geserialiseerde veld vertegenwoordigt. U kunt ook methoden markeren met deze annotatie. Als u dat doet, wordt hun retourwaarde tijdens serialisatie omgezet in een JSON-eigenschap:


class Book {
	@JsonProperty("name")
	public String title;
	public String author;
	public int pages;
 
	@JsonProperty("quotedTitle")
	public String getQuotedTitle() {
    	    return "\"" + title + "\"";
	}
}

Resultaat van seralisatie:

{
  "author" : "Pratchett T., Gaiman N.",
  "pages" : 383,
  "name" : "Good Omens",
  "quotedTitle" : "\"Good Omens\""
}

@JsonInclude — Met deze annotatie kunt u voorwaarden specificeren waaraan moet worden voldaan voordat een veld kan worden geserialiseerd. U kunt het toepassen op afzonderlijke velden of op een hele klas. Laten we eerst proberen een object te serialiseren met niet-geïnitialiseerde velden:


public class Solution {
	public static void main(String[] args) throws Exception {
    		Book book = new Book();

    		ObjectMapper mapper = new ObjectMapper();
    		mapper.enable(SerializationFeature.INDENT_OUTPUT);
    		String jsonBook = mapper.writeValueAsString(book);
    		System.out.println(jsonBook);
	}
}

Resultaat van seralisatie:

{
  "titel": null,
  "auteur": null,
  "pagina's": 0
}

En als je de annotatie toevoegt:


@JsonInclude(JsonInclude.Include.NON_NULL)
class Book {
	public String title;
	public String author;
	public int pages;
}

Dan krijgen we dit resultaat:

{
  "pagina's" : 0
}

Velden die null zijn, worden nu niet geserialiseerd.

@JsonPropertyOrder — Met deze annotatie kunt u de volgorde instellen waarin velden worden geserialiseerd:


@JsonPropertyOrder({"author", "title", "pages"})
class Book {
	public String title;
	public String author;
	public int pages;
}

Resultaat van seralisatie:

{
  "author" : "Pratchett T., Gaiman N.",
  "title" : "Good Omens",
  "pages" : 383
}

Onthoud voorlopig hoe u annotaties gebruikt. Aan het einde van deze module leren we ze beter kennen en maken we zelfs onze eigen annotaties.

Serialisatie en deserialisatie in XML

Als we moeten serialiseren naar XML, kunnen we allemaal dezelfde instellingen en annotaties gebruiken. Het enige verschil is de implementatie van demapper-object:


public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "Good Omens";
	book.author = "Pratchett T., Gaiman N.";
	book.pages = 383;
 
	ObjectMapper mapper = new XmlMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String xmlBook = mapper.writeValueAsString(book);
	System.out.println(xmlBook);
}

Uitgang:

 <Boek>
  <title>Good Omens</title>
  <author>Pratchett T., Gaiman N.</author>
  <pages>383</pages>
</Book>

Deserialisatie van XML:


public static void main(String[] args) throws Exception {
   String xmlString = """
            <Book>
             <title>Good Omens</title>
             <author>Pratchett T., Gaiman N.</author>
             <pages>383</pages>
           </Book>""";
   ObjectMapper mapper = new XmlMapper();
   Book book = mapper.readValue(xmlString, Book.class);
   System.out.println(book);
}

Serialisatie en deserialisatie in YAML

We behandelen YAML op dezelfde manier als we XML behandelen:


public static void main(String[] args) throws Exception {
	Book book = new Book();
	book.title = "Good Omens";
	book.author = "Pratchett T., Gaiman N.";
	book.pages = 383;
 
	ObjectMapper mapper = new YAMLMapper();
	mapper.enable(SerializationFeature.INDENT_OUTPUT);
	String yamlBook = mapper.writeValueAsString(book);
	System.out.println(yamlBook);
}

Uitgang:

---
titel: "Good Omens"
auteur: "Pratchett T., Gaiman N."
pagina's: 383

Deserialisatie van YAML:


public static void main(String[] args) throws Exception {
   String yamlString = """
           ---
           title: "Good Omens"
           author: "Pratchett T., Gaiman N."
           pages: 383""";
   ObjectMapper mapper = new YAMLMapper();
   Book book = mapper.readValue(yamlString, Book.class);
   System.out.println(book);
}