Jackson è una popolare libreria per la serializzazione/deserializzazione di oggetti Java in vari formati di testo. La classe ObjectMapper è il modo principale della libreria per lavorare con il formato JSON. Per altri formati, abbiamo i suoi discendenti ( XmlMapper , YAMMLMapper ). Grazie all'ereditarietà, possiamo lavorare con tutti i formati in modo coerente, attraverso un'unica interfaccia.

Scarica i file jar

Prima di studiare gli esempi, dobbiamo scaricare i file jar di Jackson e collegarli al progetto in IntelliJ IDEA. Prendiamo l'esempio di jackson-databind per vedere come cercare i file necessari:

  1. Vai al sito Web del repository Maven .

  2. Inserisci " jackson-databind " nella casella di ricerca. Otterrai quanto segue:

  3. Il primo risultato della ricerca è quello che ci interessa. Segui il link.

  4. A volte può essere necessaria una particolare versione di una libreria per garantire la compatibilità con altri componenti in un progetto. L'ultima versione dovrebbe funzionare (al momento della stesura di questa lezione, è la 2.13.2.2). Segui il link.

  5. Nella pagina che si apre, vuoi il link "bundle":

  6. Scarica il file jar usando questo link .

Seguendo una procedura simile, puoi trovare e scaricare il resto dei file jar necessari:

Dopo aver scaricato tutti i file necessari, collegali al progetto in IntelliJ IDEA:

  1. Apri le impostazioni del progetto (puoi farlo con la combinazione di tasti Ctrl+Alt+Maiusc+S ).

  2. Vai a Biblioteche .

  3. Premi + e poi "Java". Seleziona tutti i file scaricati. Ecco cosa dovremmo concludere:

  4. Questo conclude il nostro lavoro preparatorio. Ora possiamo provare ObjectMapper in azione.

Serializzazione in JSON

Innanzitutto, serializziamo alcuni oggetti in 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);
	}
}

L'esecuzione di main ti darà questo output:

{"title":"Buoni presagi","author":"Pratchett T., Gaiman N.","pages":383}

L' ObjectMapper ha molte impostazioni avanzate. Usiamone uno per rendere più leggibile la stringa JSON. Dopo aver creato ilObjectMapperoggetto, eseguire questa istruzione:

mapper.enable(SerializationFeature.INDENT_OUTPUT);

Le informazioni nell'output rimangono le stesse, ma ora sono presenti indentazione e interruzioni di riga:

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

Deserializzazione da JSON

Ora facciamo l'azione opposta: deserializzeremo una stringa in un oggetto. Per poter vedere cosa sta facendo il programma, eseguiamo l'override del metodo toString nella classe Book :

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

E faremo quanto segue nel metodo principale :

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);
}

Produzione:

Libro{title='Buoni presagi', author='Pratchett T., Gaiman N.', pagine=383}

Il metodo readValue è sovraccarico: ha molte varianti che accettano un file, un collegamento, vari flussi di input, ecc. Per semplicità, il nostro esempio utilizza una variante che accetta una stringa JSON.

Come accennato in precedenza, ObjectMapper ha molte impostazioni. Diamo un'occhiata ad alcuni di loro.

Ignorando le proprietà sconosciute

Considera una situazione in cui una stringa JSON ha una proprietà che non esiste nella classe 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);
}

L'esecuzione di questo codice genera un'eccezione UnrecognizedPropertyException . Questo è il comportamento predefinito, ma possiamo cambiarlo:

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

Quando si crea un fileObjectMapperoggetto, utilizziamo il metodo configure per impostare l'impostazione corrispondente su false . Il metodo configure modifica l'oggetto su cui è stato chiamato e quindi restituisce lo stesso oggetto, quindi possiamo effettuare questa chiamata in un modo diverso:

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

In termini di funzionalità, questa notazione è uguale alla precedente.

Se ora eseguiamo il metodo main , la deserializzazione avrà esito positivo e la proprietà unknown verrà ignorata.

Comode annotazioni

Jackson ci fornisce diverse annotazioni che ci consentono di personalizzare il processo di serializzazione in tutti i modi. Diamo un'occhiata ad alcuni dei più utili:

@JsonIgnore — Questa annotazione è posizionata sopra un elemento che deve essere ignorato durante la serializzazione/deserializzazione:

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

Qui ilautoreIl campo non verrà incluso nel JSON risultante durante la serializzazione. Dopo la deserializzazione, ilautorefield otterrà il valore predefinito (null), anche se il JSON aveva un valore diverso.

@JsonFormat : questa annotazione consente di impostare il formato dei dati serializzati. Aggiungiamo un altro campo, a Date , alla classe Book :

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

Dopo la serializzazione, otteniamo il seguente JSON:

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

Come puoi vedere, la data è stata serializzata come numero. Aggiungeremo un'annotazione e imposteremo il formato:

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();
}

Ora il risultato della serializzazione è:

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

@JsonProperty : questa annotazione consente di modificare il nome della proprietà che rappresenta il campo serializzato. Puoi anche contrassegnare i metodi con questa annotazione. Se lo fai, il loro valore restituito verrà convertito in una proprietà JSON durante la serializzazione:

class Book {
	@JsonProperty("name")
	public String title;
	public String author;
	public int pages;

	@JsonProperty("quotedTitle")
	public String getQuotedTitle() {
    	    return "\"" + title + "\"";
	}
}

Risultato della seralizzazione:

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

@JsonInclude : utilizzando questa annotazione, puoi specificare le condizioni che devono essere soddisfatte affinché un campo venga serializzato. Puoi applicarlo a singoli campi o a un'intera classe. Innanzitutto, proviamo a serializzare un oggetto con campi non inizializzati:

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);
	}
}

Risultato della seralizzazione:

{
  "titolo" : null,
  "autore" : null,
  "pagine" : 0
}

E se aggiungi l'annotazione:

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

Quindi otteniamo questo risultato:

{
  "pagine" : 0
}

Ora i campi nulli non vengono serializzati.

@JsonPropertyOrder — Questa annotazione consente di impostare l'ordine in cui i campi vengono serializzati:

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

Risultato della seralizzazione:

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

Per ora, ricorda solo come utilizzare le annotazioni. Alla fine di questo modulo, li conosceremo meglio e creeremo anche le nostre annotazioni.

Serializzazione e deserializzazione in XML

Se abbiamo bisogno di serializzare in XML, possiamo utilizzare tutte le stesse impostazioni e annotazioni. L'unica differenza sarà l'implementazione deloggetto mappatore:

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);
}

Produzione:

 <Book>
  <title>Buoni presagi</title>
  <author>Pratchett T., Gaiman N.</author>
  <pages>383</pages>
</Book>

Deserializzazione di 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);
}

Serializzazione e deserializzazione in YAML

Gestiamo YAML nello stesso modo in cui gestiamo XML:

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);
}

Produzione:

---
titolo: "Good Omens"
autore: "Pratchett T., Gaiman N."
pagine: 383

Deserializzazione di 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);
}