Jackson est une bibliothèque populaire pour la sérialisation/désérialisation d'objets Java dans divers formats de texte. La classe ObjectMapper est le principal moyen de la bibliothèque de travailler avec le format JSON. Pour les autres formats, nous avons ses descendants ( XmlMapper , YAMLMapper ). Grâce à l'héritage, nous pouvons travailler avec tous les formats de manière cohérente, via une interface unique.

Télécharger les fichiers jar

Avant d'étudier les exemples, nous devons télécharger les fichiers jar Jackson et les connecter au projet dans IntelliJ IDEA. Prenons l'exemple de jackson-databind pour voir comment rechercher les fichiers nécessaires :

  1. Accédez au site Web Maven Repository .

  2. Entrez " jackson-databind " dans le champ de recherche. Vous obtiendrez ce qui suit :

  3. Le premier résultat de recherche est ce qui nous intéresse. Suivez le lien.

  4. Parfois, une version particulière d'une bibliothèque peut être requise pour assurer la compatibilité avec d'autres composants d'un projet. La dernière version devrait fonctionner (au moment de la rédaction de cette leçon, il s'agit de la 2.13.2.2). Suivez le lien.

  5. Sur la page qui s'ouvre, vous voulez le lien "bundle":

  6. Téléchargez le fichier jar en utilisant ce lien .

En suivant une procédure similaire, vous pouvez rechercher et télécharger le reste des fichiers jar nécessaires :

Après avoir téléchargé tous les fichiers nécessaires, connectez-les au projet dans IntelliJ IDEA :

  1. Ouvrez les paramètres du projet (vous pouvez le faire avec la combinaison de touches Ctrl+Alt+Maj+S ).

  2. Allez dans Bibliothèques .

  3. Appuyez sur + puis "Java". Sélectionnez tous les fichiers téléchargés. Voici ce à quoi nous devrions nous retrouver :

  4. Cela conclut notre travail préparatoire. Nous pouvons maintenant essayer ObjectMapper en action.

Sérialisation vers JSON

Commençons par sérialiser un objet en 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'exécution de main vous donnera cette sortie :

{"title":"De bons présages","author":"Pratchett T., Gaiman N.","pages":383}

L' ObjectMapper a beaucoup de paramètres avancés. Utilisons l'un d'eux pour rendre la chaîne JSON plus lisible. Après avoir créé leObjectMappeurobjet, exécutez cette instruction :

mapper.enable(SerializationFeature.INDENT_OUTPUT);

Les informations dans la sortie restent les mêmes, mais il y a maintenant une indentation et des sauts de ligne :

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

Désérialisation depuis JSON

Faisons maintenant l'action inverse : nous allons désérialiser une chaîne en objet. Pour pouvoir voir ce que fait le programme, redéfinissons la méthode toString dans la classe Book :


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

Et nous ferons ce qui suit dans la méthode main :


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

Sortir:

Livre{title='Good Omens', author='Pratchett T., Gaiman N.', pages=383}

La méthode readValue est surchargée - elle a de nombreuses variantes qui prennent un fichier, un lien, divers flux d'entrée, etc. Pour plus de simplicité, notre exemple utilise une variante qui accepte une chaîne JSON.

Comme mentionné ci-dessus, ObjectMapper a de nombreux paramètres. Regardons quelques-uns d'entre eux.

Ignorer les propriétés inconnues

Considérez une situation où une chaîne JSON a une propriété qui n'existe pas dans la 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'exécution de ce code nous donne une UnrecognizedPropertyException . C'est le comportement par défaut, mais nous pouvons le changer :


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

Lors de la création d'unObjectMappeurobjet, nous utilisons la méthode configure pour définir le paramètre correspondant sur false . La méthode configure modifie l'objet sur lequel elle a été appelée, puis renvoie ce même objet, nous pouvons donc effectuer cet appel d'une manière différente :


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

En termes de fonctionnalité, cette notation est identique à la précédente.

Si nous exécutons maintenant la méthode principale , la désérialisation réussira et la propriété inconnue sera ignorée.

Annotations pratiques

Jackson nous fournit plusieurs annotations qui nous permettent de personnaliser le processus de sérialisation de toutes sortes de manières. Jetons un coup d'œil à certains des plus utiles :

@JsonIgnore — Cette annotation est placée au-dessus d'un élément qui doit être ignoré lors de la sérialisation/désérialisation :


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

Ici leauteurne sera pas inclus dans le JSON résultant lors de la sérialisation. Lors de la désérialisation, leauteurobtiendra la valeur par défaut (null), même si le JSON avait une valeur différente.

@JsonFormat — Cette annotation vous permet de définir le format des données sérialisées. Ajoutons un champ supplémentaire, un Date , à la classe Book :


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

Après sérialisation, nous obtenons le JSON suivant :

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

Comme vous pouvez le voir, la date a été sérialisée sous forme de nombre. Nous allons ajouter une annotation et définir le format :


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

Maintenant, le résultat de la sérialisation est :

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

@JsonProperty — Cette annotation vous permet de modifier le nom de la propriété représentant le champ sérialisé. Vous pouvez également marquer des méthodes avec cette annotation. Si vous le faites, leur valeur de retour sera convertie en une propriété JSON lors de la sérialisation :


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

Résultat de la sérialisation :

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

@JsonInclude — À l'aide de cette annotation, vous pouvez spécifier les conditions qui doivent être remplies pour qu'un champ soit sérialisé. Vous pouvez l'appliquer à des champs individuels ou à une classe entière. Essayons d'abord de sérialiser un objet avec des champs non initialisés :


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

Résultat de la sérialisation :

{
  "titre" : nul,
  "auteur" : nul,
  "pages" : 0
}

Et si vous ajoutez l'annotation :


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

On obtient alors ce résultat :

{
  "page" : 0
}

Désormais, les champs nuls ne sont pas sérialisés.

@JsonPropertyOrder — Cette annotation vous permet de définir l'ordre dans lequel les champs sont sérialisés :


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

Résultat de la sérialisation :

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

Pour l'instant, rappelez-vous simplement comment utiliser les annotations. A la fin de ce module, nous apprendrons à mieux les connaître et même à créer nos propres annotations.

Sérialisation et désérialisation en XML

Si nous devons sérialiser en XML, nous pouvons utiliser tous les mêmes paramètres et annotations. La seule différence sera la mise en œuvre de laobjet mappeur :


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

Sortir:

 <Livre>
  <title>De bons présages</title>
  <author>Pratchett T., Gaiman N.</author>
  <pages>383</pages>
</Book>

Désérialisation de 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);
}

Sérialisation et désérialisation dans YAML

Nous traitons YAML de la même manière que nous traitons 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);
}

Sortir:

---
titre : "Good Omens"
auteur : "Pratchett T., Gaiman N."
page : 383

Désérialisation de 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);
}