Conversion entre JSON et structures Java (Beans, Listes, Maps)

Principes de sérialisation JSON en Java

Le format JSON s'est imposé comme le standard d'échange de données dans les architectures distribuées. En Java, la transformation entre chaînes JSON et structures natives (objets métier, collections, tableaux) nécessite généralement l'intervention de bibliothèques de mappage. Ce document détaille les mécanismes de conversion via deux approches : l'API historique json-lib et le moteur moderne Jackson.

1. Manipulation avec json-lib

La bibliothèque json-lib repose principalement sur les classes JSONObject et JSONArray. Bien que moins utilisée aujourd'hui, elle illustre clairement la distinction structurelle entre un objet JSON {} et un tableau JSON [].

Conversion Bean vers JSON

Un objet Java standard peut être sérialisé indifféremment en objet ou en tableau JSON. La structure de sortie dépend de la classe utilitaire invoquée.

public class DemoJsonLib {
    public static void serialiserBean() {
        ProfilUtilisateur profil = new ProfilUtilisateur();
        profil.setIdentifiant("U001");
        profil.setNom("Dupont");
        profil.setLocalisation("Lyon");

        JSONObject noeudObjet = JSONObject.fromObject(profil);
        JSONArray noeudTableau = JSONArray.fromObject(profil);

        System.out.println("Format objet : " + noeudObjet.toString());
        System.out.println("Format tableau : " + noeudTableau.toString());
    }
}

Résultat en console :

Format objet : {"identifiant":"U001","localisation":"Lyon","nom":"Dupont"}
Format tableau : [{"identifiant":"U001","localisation":"Lyon","nom":"Dupont"}]

Conversion JSON vers Bean

La désérialisation nécessite de parser la chaîne source, puis d'appliquer un mappage vers la classe cible. Pour les tableaux, il faut extraire l'élément avant la conversion.

public static void deserialiserVersBean() {
    String jsonSimple = "{\"identifiant\":\"U002\",\"nom\":\"Martin\",\"localisation\":\"Paris\"}";
    String jsonTableau = "[{\"identifiant\":\"U003\",\"nom\":\"Bernard\",\"localisation\":\"Marseille\"}]";

    JSONObject objetParse = JSONObject.fromObject(jsonSimple);
    ProfilUtilisateur p1 = (ProfilUtilisateur) JSONObject.toBean(objetParse, ProfilUtilisateur.class);

    JSONArray tableauParse = JSONArray.fromObject(jsonTableau);
    JSONObject premierItem = (JSONObject) tableauParse.get(0);
    ProfilUtilisateur p2 = (ProfilUtilisateur) JSONObject.toBean(premierItem, ProfilUtilisateur.class);

    System.out.println(p1);
    System.out.println(p2);
}

Gestion des Listes et Maps

Les collections Java sont naturellement mappées vers des tableaux JSON. L'opération inverse exige une conversion explicite via les méthodes dédiées de JSONArray.

public static void gererCollections() {
    // Liste vers JSON
    List<profilutilisateur> listeProfils = new ArrayList<>();
    listeProfils.add(new ProfilUtilisateur("U004", "Leroy", "Bordeaux"));
    JSONArray jsonListe = JSONArray.fromObject(listeProfils);
    System.out.println("Liste sérialisée : " + jsonListe.toString());

    // JSON vers Liste
    String sourceJson = "[{\"identifiant\":\"U005\",\"nom\":\"Moreau\",\"localisation\":\"Nantes\"}]";
    JSONArray tableauSource = JSONArray.fromObject(sourceJson);
    List<profilutilisateur> resultatListe = (List<profilutilisateur>) JSONArray.toList(tableauSource, ProfilUtilisateur.class);
    resultatListe.forEach(System.out::println);

    // Map vers JSON
    Map<string profilutilisateur=""> carteProfils = new HashMap<>();
    carteProfils.put("admin", new ProfilUtilisateur("U006", "Dubois", "Lille"));
    JSONObject jsonMap = JSONObject.fromObject(carteProfils);
    System.out.println("Map sérialisée : " + jsonMap.toString());
}</string></profilutilisateur></profilutilisateur></profilutilisateur>

Pour restaurer une structure associative complexe depuis une chaîne JSON, json-lib impose souvent l'usage d'un contenuer intermédiaire ou d'un dicitonnaire de types lors de l'appel à toBean(), afin de résoudre les génériques à l'exécution.

2. Approche moderne avec Jackson (ObjectMapper)

Jackson est la référence actuelle pour le traitement JSON en Java. La classe centrale ObjectMapper gère automatiquement l'introspection, les génériques et les structures imbriquées sans configuration verbeuse.

Sérialisation de structures composites

La méthode writeValueAsString() accepte n'importe quelle structure Java et produit une représentation JSON optimisée.

public class MoteurJackson {
    private static final ObjectMapper CONVERTISSEUR = new ObjectMapper();

    public static void exporterVersJson() throws JsonProcessingException {
        List<contact> annuaire = Arrays.asList(
            new Contact("alice", "alice@domaine.fr", 28),
            new Contact("bob", "bob@domaine.fr", 34)
        );

        Map<string object=""> paquetDonnees = new HashMap<>();
        paquetDonnees.put("contacts", annuaire);
        paquetDonnees.put("parametres", Map.of("version", "2.1", "actif", true));
        paquetDonnees.put("indices", new int[]{10, 25, 40});

        String fluxJson = CONVERTISSEUR.writeValueAsString(paquetDonnees);
        System.out.println(fluxJson);
    }
}</string></contact>

Sortie générée :

{"contacts":[{"pseudo":"alice","courriel":"alice@domaine.fr","age":28},{"pseudo":"bob","courriel":"bob@domaine.fr","age":34}],"parametres":{"version":"2.1","actif":true},"indices":[10,25,40]}

Désérialisation typée et sécurisée

Contrairement aux approches brutes, Jackson recommande l'utilisation de TypeReference pour préserver les informatoins de type générique lors de la lecture de listes ou de maps.

public static void importerDepuisJson() throws IOException {
    String jsonListe = "[{\"pseudo\":\"charlie\",\"courriel\":\"c@test.fr\",\"age\":22},{\"pseudo\":\"dave\",\"courriel\":\"d@test.fr\",\"age\":29}]";
    String jsonMap = "{\"configuration\":{\"delai\":500,\"environnement\":\"production\"},\"statut\":\"valide\"}";

    // Lecture typée d'une liste
    List<contact> contactsRestitues = CONVERTISSEUR.readValue(
        jsonListe, 
        new TypeReference<list>>(){}
    );

    // Lecture typée d'une map imbriquée
    Map<string object=""> configRestituee = CONVERTISSEUR.readValue(
        jsonMap, 
        new TypeReference<map object="">>(){}
    );

    contactsRestitues.forEach(System.out::println);
    configRestituee.forEach((cle, valeur) -> System.out.println(cle + " => " + valeur));
}</map></string></list></contact>

Conversion vers tableaux et objets simples

Le mappage vers des tableaux Java ou des beans isolés suit la même logique, en spécifiant directement la classe cible ou le type tableau.

public static void convertirTypesSimples() throws IOException {
    String jsonBean = "{\"pseudo\":\"eve\",\"courriel\":\"e@reseau.fr\",\"age\":31}";
    String jsonTableau = "[{\"pseudo\":\"franck\",\"courriel\":\"f@reseau.fr\",\"age\":40},{\"pseudo\":\"gina\",\"courriel\":\"g@reseau.fr\",\"age\":27}]";

    Contact contactUnique = CONVERTISSEUR.readValue(jsonBean, Contact.class);
    Contact[] tableauContacts = CONVERTISSEUR.readValue(jsonTableau, Contact[].class);

    System.out.println("Bean isolé : " + contactUnique);
    System.out.println("Nombre d'éléments dans le tableau : " + tableauContacts.length);
}

L'API Jackson gère nativement les correspondances de noms de champs, les types numériques, les booléens et les structures nulles. Pour les scénarios avancés, des annotations comme @JsonProperty ou @JsonIgnore permettent d'affiner le comportement de sérialisation sans altérer la logique métier.

Étiquettes: Java JSON Jackson json-lib ObjectMapper

Publié le 21 août à 14h24