W3docs

Java JSON avec Jackson

Analysez, générez et liez du JSON en Java avec la bibliothèque Jackson — ObjectMapper et data binding.

Jackson est la bibliothèque JSON de référence pour Java. Le JDK ne fournit aucune API JSON native, aussi presque toutes les applications Spring, Quarkus ou Micronaut utilisent Jackson pour convertir des objets Java en texte JSON et inversement. Son point d'entrée est une seule classe polyvalente — ObjectMapper — qui gère les deux opérations toujours nécessaires : la sérialisation (objet Java → JSON) et la désérialisation (JSON → objet Java).

Si vous débutez avec JSON en Java, commencez par l'introduction au JSON ; pour une bibliothèque alternative plus légère, consultez le chapitre sur Gson. Cette page couvre l'ajout de Jackson, les trois niveaux de son API, le data binding, le modèle arborescent et les annotations qui contrôlent le mapping.

Ajouter Jackson à votre projet

Jackson ne fait pas partie du JDK, il faut donc le déclarer comme dépendance. L'artefact jackson-databind tire les deux autres modules principaux (jackson-core et jackson-annotations) de manière transitive.

<!-- Maven -->
<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.17.1</version>
</dependency>
// Gradle
implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.1'

Les trois façons de travailler avec JSON

Jackson expose les mêmes données de trois manières différentes. Choisissez le niveau adapté à la tâche :

ApprocheType principalQuand l'utiliser
Data bindingObjectMapper.readValue / writeValueVous avez un POJO ou un record qui reflète le JSON — le cas le plus courant
Modèle arborescentJsonNode via readTreeLa structure est dynamique ou vous n'avez besoin que de quelques champs
StreamingJsonParser / JsonGeneratorDocuments volumineux qu'on ne peut pas charger entièrement en mémoire

Le data binding est utilisé 90 % du temps ; les deux autres sont des solutions de secours.

Data binding : des objets en entrée, du JSON en sortie

ObjectMapper.writeValueAsString sérialise tout objet Java en lisant ses getters (ou ses composants de record) ; readValue fait l'inverse, en associant les noms des champs JSON à vos champs. Un record est la cible la plus propre — Jackson 2.12+ se lie à son constructeur canonique automatiquement, sans avoir à écrire de getters ni de constructeur sans argument.

import com.fasterxml.jackson.databind.ObjectMapper;

record User(String name, int age, boolean active) {}

ObjectMapper mapper = new ObjectMapper();

// serialize: Java -> JSON
User ada = new User("Ada", 36, true);
String json = mapper.writeValueAsString(ada);
// {"name":"Ada","age":36,"active":true}

// deserialize: JSON -> Java
User back = mapper.readValue(json, User.class);
System.out.println(back.name()); // Ada

Pour les collections et les génériques, passez à Jackson une TypeReference afin que le type d'élément survive à l'effacement de type :

import com.fasterxml.jackson.core.type.TypeReference;

List<User> users = mapper.readValue(jsonArray, new TypeReference<List<User>>() {});

Le modèle arborescent : quand la structure est inconnue

Lorsque vous n'avez pas (ou ne souhaitez pas) de classe correspondante, analysez le JSON dans un arbre générique JsonNode et naviguez-y par clé. Cela ressemble à ce que ferait un parseur Map/List artisanal, mais avec des accesseurs typés comme asInt() et asText().

import com.fasterxml.jackson.databind.JsonNode;

JsonNode root = mapper.readTree(json);
String name = root.get("name").asText();
int age     = root.get("age").asInt();
JsonNode first = root.get("languages").get(0); // array access by index

Contrôler le mapping avec les annotations

Les noms de champs JSON correspondent rarement parfaitement aux conventions Java. Quelques annotations comblent cet écart sans modifier vos noms de champs :

AnnotationEffet
@JsonProperty("user_name")Associer un champ à une clé JSON différente
@JsonIgnoreExclure un champ dans les deux sens
@JsonInclude(NON_NULL)Supprimer les champs null de la sortie
@JsonCreator / @JsonFormatConstruction personnalisée / formatage de date
record Account(
    @JsonProperty("user_name") String userName,
    @JsonIgnore String passwordHash) {}

Un exemple complet : sérialiser, analyser et lier manuellement

Jackson n'est pas disponible sur le classpath de ce runner, le programme ci-dessous reproduit donc les mêmes concepts — un writer JSON, un parseur récursif dans un arbre Map/List, et la liaison dans un record — en utilisant uniquement java.util. C'est exactement ce que fait ObjectMapper sous le capot : parcourir un graphe d'objets pour émettre du texte, et tokeniser le texte pour reconstruire un arbre.

java— editable, runs on the server

Ce qu'il faut retenir de l'exécution :

  • La sérialisation parcourt un graphe d'objets et émet du texte. La ligne serialized montre un Map/List imbriqué rendu en {"name":"Ada",...,"languages":["Java","Ada"]} — un tableau dans un objet. ObjectMapper.writeValueAsString effectue le même parcours récursif sur les getters de votre POJO ou les composants d'un record.
  • L'analyse reconstruit d'abord un arbre générique. Le type d'exécution de la valeur analysée est LinkedHashMap, pas User — exactement le modèle arborescent de Jackson, où readTree vous donne un JsonNode que vous naviguez par clé avant qu'une classe soit impliquée.
  • Les nombres JSON deviennent des nombres Java, avec un choix de type. Le champ age est revenu comme Integer (42) parce que le texte n'avait pas de virgule décimale ; le parseur a choisi Integer plutôt que Double. Jackson fait le même choix, c'est pourquoi un champ int se lie proprement tandis que 3.14 atterrirait comme Double.
  • L'accès aux champs se fait par nom, et l'ordre est préservé. L'utilisation de LinkedHashMap a conservé les clés dans l'ordre d'insertion, donc name est lu avant age. Jackson préserve l'ordre des clés d'objet de la même façon, c'est pourquoi le JSON après un aller-retour ressemble à l'original.
  • L'aller-retour est sans perte quand le modèle correspond. La dernière ligne a re-sérialisé l'arbre analysé vers le même JSON d'origine, et le record typé User a lié correctement name, age et languages — tout l'intérêt du data binding : texte en entrée, objet en sortie, texte à nouveau, sans dérive.

Pratique

Pratique
Avec Jackson, vous recevez une réponse JSON dont vous ne contrôlez pas la structure et vous n'avez besoin de lire que deux champs dans un document volumineux et profondément imbriqué. Quelle approche convient le mieux ?
Avec Jackson, vous recevez une réponse JSON dont vous ne contrôlez pas la structure et vous n'avez besoin de lire que deux champs dans un document volumineux et profondément imbriqué. Quelle approche convient le mieux ?
Was this page helpful?