Ajouter des chaînes de caractères vides dans un objet JSON

En travaillant sur un projet ce matin, nous avons constaté que la librairie JSON fournie avec Delphi ne permettait pas d'ajouter de chaines de caractères vides dans un objet.

Ce dysfonctionnement est causé par la fonction TJSONObject.AddPair de System.JSON. Voici le bout de code incriminé :


function TJSONObject.AddPair(const Str: string; const Val: string): TJSONObject;
begin
  if (not Str.IsEmpty) and (not Val.IsEmpty) then
    AddPair(TJSONPair.Create(Str, Val));
  Result := Self;
end;

Facile de repérer l'erreur lorsqu'on s'y retrouve un peu en Pascal, mais voilà, comment contourner le problème sans personnaliser la librairie JSON fournie et sortir de la version officielle maintenue par Embarcadero ?
Dans ce cas précis, la réponse est assez simple. Je vais y revenir.

Ce dysfonctionnement a été corrigé amélioré depuis la version 10.2 Tokyo.
Cependant si vous utilisez Firemonkey pour des développements Android il est prudent d'attendre un prochain patch. A l'heure actuelle, sur certains projets, la 10.2 Tokyo affiche des écrans noirs sous Android au lieu des composants qui devraient y être. Le patch est dans les tuyaux, Marco Cantu l'a annoncé il y a quelques jours.
A priori si vous utilisez la VCL, pas de soucis à basculer sur cette version de Delphi ou de RAD Studio pour bénéficier de toutes ses fonctionnalités (corrections, améliorations et nombreuses nouveautés autour de Windows 10).

Pour en revenir à notre bogue, l'erreur qui nous dérangeait se reproduit facilement. Il suffit de construire un objet JSON et de lui ajouter des paires clé/valeurs dont l'une avec une valeur non renseignée comme ici :


procedure TForm1.Button1Click(Sender: TObject);
var
  json: tjsonobject;
begin
  json := tjsonobject.Create;
  try
    json.AddPair('hello', 'world');
    json.AddPair('goodbye', '');
    json.AddPair('good', 'night');
    Memo1.Lines.Add(json.ToJSON);
  finally
    json.Free;
  end;
end;

Le hic, c'est que ce code ne permet plus de dialoguer avec un service web ou une autre application qui attendrait d'avoir les trois propriétés dans l'objet transmis. En effet il omet les propriétés vides :


{"hello":"world","good":"night"}

Bien entendu, s'il est bien fait, le site ou le logiciel lisant le résultat devrait s'assurer que toutes les propriétés sont renseignées et qu'elles ont bien la valeur qu'il espère ou les initialiser s'il peut les traiter de façon facultative. Problème : tous les développeurs n'ont pas la même vision des choses et il est donc fortement recommandé de fournir ce qui est demandé par la partie adverse, même si on estime qu'elle peut faire un bout du chemin.

Pour corriger le soucis, nous avons donc opté pour une méthode qui fonctionne, sans sortir de la librairie standard. Il a suffit de créer un objet tJSONPair, dont on peut initialiser les deux parties de façon séparée, et de l'ajouter à notre tJSONObject.


procedure TForm1.Button2Click(Sender: TObject);
var
  json: tjsonobject;
  pair: tjsonpair;
begin
  json := tjsonobject.Create;
  try
    json.AddPair('hello', 'world');
    pair := tjsonpair.Create;
    pair.JsonString := tjsonstring.Create('goodbye');
    pair.JsonValue := tjsonstring.Create('');
    json.AddPair(pair);
    json.AddPair('good', 'night');
    Memo1.Lines.Add(json.ToJSON);
  finally
    json.Free;
  end;
end;

Le résultat final propose ainsi les trois propriétés attendues et permet de transmettre les valeurs vides :


{"hello":"world","goodbye":"","good":"night"}

Si vous tombez dans ce piège, idéalement pensez à ajouter un TODO à votre projet pour modifier le bloc de code concerné afin de revenir à quelque chose de plus lisible dès que vous passerez à la 10.2 Tokyo ou une version ultérieure.

Moins il y a de lignes de codes de bidouillage, plus lisible est le projet et mieux se portent sa maintenance et sa survie sur le long terme.


A lire aussi

Plutôt INI ou JSON pour stocker vos paramètres ? (21/07/2017)
Calculer et vérifier un checksum pour dialoguer avec l'extérieur (19/07/2017)
Télécharger simplement un fichier via Internet en tâche de fond (10/07/2017)
Calculer un MD5 sous Delphi (04/07/2017)
Les threads et le blocage des écrans (14/06/2017)
Utilisation de processus sous Delphi : fonctionnement de base. (04/06/2017)
Passer un traitement lourd en tâche de fond sans bloquer l'écran (04/06/2017)
Ajouter des chaînes de caractères vides dans un objet JSON (19/05/2017)
Configurer le firewall de McAfee AntiVirus Plus pour utiliser l'App Tethering (28/06/2016)