Problèmes majeurs d’encodage/json

Le paquet encoding/json accepte des entrées qui violent la RFC 8259 : il ne signale pas les séquences UTF‑8 invalides et laisse passer des objets contenant des clés dupliquées. Cette dernière faiblesse a déjà été exploitée (CVE‑2017‑12635) et constitue un vecteur d’injection dans les applications de sécurité. De plus, les slices ou maps nil sont sérialisés en null, alors que la plupart des développeurs Go préfèrent obtenir [] ou {}. L’unmarshalling est case‑insensible, ce qui crée des ambiguïtés de correspondance entre les champs de structure et les noms JSON, et entraîne une surcharge de comparaison. Enfin, les méthodes MarshalJSON et UnmarshalJSON sont appelées de façon incohérente selon que le récepteur est un pointeur ou non, ce qui rend le comportement imprévisible.

Architecture de l’API JSON v2

Le nouveau namespace encoding/json/v2, introduit avec encoding/json/jsontext, sépare clairement la couche syntaxique (analyse du texte) de la couche sémantique (conversion Go↔JSON). Le package jsontext fournit des fonctions de lecture/écriture tokenisées qui opèrent directement sur io.Reader ou io.Writer sans charger le document complet en mémoire. Les options – par exemple DisallowUnknownFields – sont désormais passées explicitement aux fonctions Marshal et Unmarshal, ce qui évite la perte d’effet lorsqu’un type implémente UnmarshalJSON. Cette refonte permet également d’utiliser des buffers personnalisés au lieu du bytes.Buffer fixe des fonctions Compact, Indent et HTMLEscape.

Améliorations concrètes et performances

Les nouvelles implémentations rejettent systématiquement les caractères UTF‑8 invalides et les clés dupliquées, alignant le comportement sur la norme Internet. Les slices et maps nil sont encodés en tableau ou objet vide, éliminant les erreurs de désérialisation inter‑langages. Le décodage est désormais strictement token‑based ; la méthode Decoder.Token a été optimisée pour éviter les allocations superflues, et une API symétrique Encoder.Token a été ajoutée pour l’écriture progressive. Le double parsing imposé par UnmarshalJSON a été supprimé : le texte JSON est analysé une seule fois avant d’appeler le code utilisateur, ce qui réduit la complexité de O(n²) à O(n). En pratique, les benchmarks de Go 1.27 montrent une réduction de 30 % du temps de marshaling pour des structures de taille moyenne et une consommation mémoire jusqu’à 40 % moindre.

json.NewDecoder(r).Decode(v)