Gestion de la sérialisation LocalDateTime avec Jackson en Java 8

Lors de l'utilisation de Jackson pour manipuler des objets Java 8, une erreur classique suvrient fréquemment lors de la conversion de types temporels comme LocalDateTime. Ce problème se manifeste généralement par une exception bloquante lorsque l'on tente de transformer un POJO en Map ou en flux JSON.

Analyse de l'exception technique

L'erreur se produit souvent dans des utilitaires de conversion générique utilisant la méthode convertValue. Voici le message d'erreur type :

java.lang.IllegalArgumentException: Java 8 date/time type `java.time.LocalDateTime` not supported by default: 
add Module "com.fasterxml.jackson.datatype:jackson-datatype-jsr310"

Ce comportement s'explique par le fait que le noyau de Jackson ne possède pas de stratégie native pour traiter l'API java.time introduite avec Java 8. Sans module spécifique, le moteur de sérialisation échoue à interpréter ces types de données complexes.

Mise en œuvre de la solution

1. Dépendance Maven

La première étape consiste à intégrer le module de support des types de données JSR-310 dans votre fichier pom.xml. Veillez à ce que la version corresponde à celle de votre bibliothèque jackson-databind principale.

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.17.1</version>
</dependency>

2. Configuration de l'ObjectMapper

Pour résoudre le problème de manière globale au sein d'un utilitaire, il est nécessaire d'enregistrer explicitement le module JavaTimeModule et de configurer le format de sortie pour éviter l'affichage sous forme de timestamps numériques.

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.annotation.JsonInclude;

import java.util.Map;
import java.util.HashMap;
import java.util.Collections;

public class DataTransformUtils {

    private static final ObjectMapper MAPPER = configureMapper();

    private static ObjectMapper configureMapper() {
        ObjectMapper mapper = new ObjectMapper();
        // Activation du support pour Java 8 Date/Time
        mapper.registerModule(new JavaTimeModule());
        // Désactivation de l'écriture des dates en tant que timestamps pour privilégier le format ISO-8601
        mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        // Exclusion des valeurs nulles pour alléger le résultat
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        // Éviter les erreurs sur les beans vides
        mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
        return mapper;
    }

    /**
     * Convertit un objet Java en Map pour un traitement flexible (ex: export Excel)
     */
    public static Map<String, Object> transformToMap(Object source) {
        if (source == null) {
            return Collections.emptyMap();
        }
        return MAPPER.convertValue(source, Map.class);
    }
}

Intégration dans un processus d'exportation

Dans un contexte d'exportation de données (comme la génération de fichiers Excel), l'utilisation de cet utilitaire permet de garantri que les colonnes de type temporel sont correctement formatées en chaînes de caractères lisibles.

public void exportDataToSheet(List<Object> records) {
    for (Object record : records) {
        Map<String, Object> rowData = DataTransformUtils.transformToMap(record);
        // Accès sécurisé à la date formatée
        Object creationDate = rowData.get("createdAt");
        System.out.println("Date formatée : " + creationDate); 
        // Affiche par exemple : 2024-05-20T14:30:00
    }
}

Points de vigilance

  • Incohérence de version : L'utilisation de versions disparates entre le module JSR-310 et le databind peut provoquer des erreurs de type NoSuchMethodError.
  • Formatage : Si vous oubliez de désactiver WRITE_DATES_AS_TIMESTAMPS, vos dates apparaîtront sous forme de tableaux d'entiers ou de longues valeurs numériques dans vos exports.
  • Injection Spring : Si vous utilisez Spring Boot, il est souvent préférable de configurer un Bean ObjectMapper personnalisé via une @Configuration pour que toutes les sérialisations de l'application bénéficient de ces réglages automatiquement.

Étiquettes: Java Jackson serialization LocalDateTime jsr310

Publié le 26 octobre à 13h53