Optimisation de la manipulation JSON en Delphi via une interface orientée objet intuitive

Présentation de la bibliothèque d'abstraction JSON

Cette bibliothèque Delphi offre une couche d'abstraction élégante au-dessus de l'unité standard System.JSON. Elle a été conçue pour simplifier l'interaction avec les structures JSON grâce à une API fluide et fortement typée.

Caractéristiques principales

  • Accès typé direct : Lecture et écriture via des propriétés indexées spécifiques (S, I, L, F, B, D).
  • Gestion des dates : Conversion automatique au format ISO 8601 avec prise en charge des fuseaux horaires.
  • API fluide (Fluent API) : Possibilité d'enchaîner les appels pour un code plus concis.
  • Gestion mémoire automatique : Utilisation des interfaces et du comptage de références, éliminant les fuites de mémoire.
  • Structures imbriquées : Création et navigation aisées dans les objets et tableaux multi-niveaux.
  • Navigasion par chemin : Accès direct via des expressions de type user.address.city ou items.0.id.
  • Gestion des valeurs nulles : Méthodes dédiées pour vérifier et définir les états null.
  • Extraction sécurisée : Méthodes TryGet* pour éviter les exceptions en cas de clé manquante.
  • Persistance fichier : Sauvegarde et chargement directs depuis le système de fichiers.
  • Aucune dépendance externe : Repose exclusivement sur la RTL de Delphi.

Guide d'utilisation

Initialisation et assignation de valeurs

uses
  SimpleJSON;

var
  Payload: IJson;
begin
  Payload := TJson.Create;
  
  // Assignation de données typées
  Payload.S['username'] := 'Alice';
  Payload.I['score'] := 150;
  Payload.L['transaction_id'] := 9876543210987; // Entier 64 bits
  Payload.F['balance'] := 1250.75;
  Payload.B['is_verified'] := True;
  Payload.D['last_login'] := Now;
  
  // Extraction des données
  WriteLn(Payload.S['username']);
  WriteLn(IntToStr(Payload.I['score']));
  
  // La libération de la mémoire est gérée automatiquement par l'interface
end;

Analyse d'une chaîne JSON

var
  DataDoc: IJson;
begin
  DataDoc := TJson.Parse('{"product_id":502,"label":"Clavier","cost":45.50}');
  if Assigned(DataDoc) then
    WriteLn(DataDoc.S['label']);  // Affiche: Clavier
end;

Traitement des dates et heures

var
  EventData: IJson;
begin
  EventData := TJson.Create;
  
  // Les valeurs TDateTime sont sérialisées en ISO 8601
  EventData.D['start_date'] := Now;
  EventData.D['birth_date'] := EncodeDate(1985, 8, 20);
  
  WriteLn(DateTimeToStr(EventData.D['start_date']));
  
  // Analyse d'une chaîne avec fuseau horaire
  EventData := TJson.Parse('{"meeting":"Sync","timestamp":"2024-03-10T14:00:00+01:00"}');
  WriteLn(DateTimeToStr(EventData.D['timestamp']));
end;

Formats de date reconnus :

  • ISO 8601 avec millisecondes : 2024-03-10T14:00:00.000
  • ISO 8601 standard : 2024-03-10T14:00:00
  • Avec décalage horaire : 2024-03-10T14:00:00+01:00
  • Indicateur UTC : 2024-03-10T14:00:00Z
  • Date seule : 2024-03-10

Gestion des valeurs nulles

var
  RecordJson: IJson;
begin
  RecordJson := TJson.Create;
  
  RecordJson.SetNull('cancellation_date');
  
  if RecordJson.IsNull('cancellation_date') then
    WriteLn('La date d''annulation est nulle');
  
  // Null dans un tableau
  RecordJson.A['events'].AddNull;
  if RecordJson.A['events'].IsNull(0) then
    WriteLn('Le premier événement est nul');
end;

Extraction sécurisée (TryGet)

var
  UserData: IJson;
  CityName: string;
  UserAge: Integer;
begin
  UserData := TJson.Parse('{"city":"Lyon","age":32}');
  
  if UserData.TryGetS('city', CityName) then
    WriteLn('Ville: ' + CityName);
  
  if UserData.TryGetI('age', UserAge) then
    WriteLn('Âge: ' + IntToStr(UserAge));
  
  if not UserData.TryGetS('email', CityName) then
    WriteLn('Clé manquante');
end;

Objets et tableaux imbriqués

var
  Profile: IJson;
  Idx: Integer;
begin
  Profile := TJson.Create;
  
  // Création implicite d'objets imbriqués
  Profile.O['location'].S['country'] := 'France';
  Profile.O['location'].S['postal_code'] := '69000';
  
  WriteLn(Profile.O['location'].S['country']);
  
  // Manipulation de tableaux avec chaînage
  Profile.A['skills']
    .Add('Delphi')
    .Add('C++')
    .Add('SQL');
    
  for Idx := 0 to Profile.A['skills'].Count - 1 do
    WriteLn(Profile.A['skills'].S[Idx]);
    
  // Ajout d'objets dans un tableau
  Profile.A['contacts'].AddObject.S['type'] := 'email';
  Profile.A['contacts'].O[0].S['value'] := 'alice@example.com';
end;

Accès par chemin (Path)

var
  Config: IJson;
begin
  Config := TJson.Create;
  Config.S['app_name'] := 'MonApp';
  Config.O['database'].S['host'] := 'localhost';
  Config.A['ports'].Add(8080).Add(8443);
  
  WriteLn(Config.Path['app_name']);          // MonApp
  WriteLn(Config.Path['database.host']);     // localhost
  WriteLn(Config.Path['ports.1']);           // 8443
end;

Persistance sur disque

var
  Settings: IJson;
begin
  Settings := TJson.Create;
  Settings.S['theme'] := 'dark';
  Settings.I['timeout'] := 30;
  Settings.SaveToFile('app_config.json');
  
  // Rechargement
  Settings := TJson.LoadFromFile('app_config.json');
  WriteLn(Settings.S['theme']);
end;

Référence de l'API

Interface IJson

Membre Descriptoin
S[Key] Lecture/écriture de chaînes
I[Key] Lecture/écriture d'entiers 32 bits
L[Key] Lecture/écriture d'entiers 64 bits
F[Key] Lecture/écriture de nombres à virgule flottante
B[Key] Lecture/écriture de booléens
D[Key] Lecture/écriture de dates (ISO 8601)
O[Key] Accès à un sous-objet
A[Key] Accès à un tableau
Path[Expr] Navigation par chemin
IsNull(Key) Vérifie si la valeur est nulle
SetNull(Key) Définit la valeur comme nulle
TryGet*(...) Méthodes d'extraction sécurisée (S, I, L, F, B, D)
Contains(Key) Vérifie l'existence d'une clé
Remove(Key) Supprime une clé
Clear Vide l'objet
GetKeys Retourne la liste des clés
Count Nombre de propriétés
ToJSON Sérialisation compacte
Format Sérialisation formatée (indentée)
SaveToFile Écriture dans un fichier

Interface IJsonArray

Membre Description
S/I/L/F/B/D[Index] Accès typé aux éléments du tableau
O[Index] Accès à un objet dans le tableau
IsNull(Index) Vérifie si un élément est nul
Add(Value) Ajoute un élément (retourne Self pour chaînage)
AddNull Ajoute une valeur nulle
AddObject Ajoute et retourne un nouvel objet
AddArray Ajoute et retourne un nouveau tableau
Delete(Index) Supprime un élément
Clear Vide le tableau
Count Nombre d'éléments
ToJSON / Format Sérialisation du tableau

Méthodes de classe

Méthode Description
TJson.Create Instancie un objet JSON vide
TJson.Parse Analyse une chaîne JSON
TJson.ParseFile / LoadFromFile Charge et analyse un fichier JSON
TJsonArray.Create Instancie un tableau JSON vide
TJsonArray.Parse Analyse une chaîne de tableau JSON

Comparaison avec l'API native System.JSON

Approche native

var
  NativeObj: TJSONObject;
begin
  NativeObj := TJSONObject.Create;
  try
    NativeObj.AddPair('username', TJSONString.Create('Alice'));
    NativeObj.AddPair('score', TJSONNumber.Create(150));
    WriteLn(NativeObj.GetValue<string>('username'));
  finally
    NativeObj.Free;
  end;
end;

Approche avec la bibliothèque d'abstraction

var
  WrapperDoc: IJson;
begin
  WrapperDoc := TJson.Create;
  WrapperDoc.S['username'] := 'Alice';
  WrapperDoc.I['score'] := 150;
  WriteLn(WrapperDoc.S['username']);
  // Libération automatique, pas de bloc try..finally requis
end;

Configuration et compilation

Ce composant nécessite Delphi 10.4 Sydney ou une version ultérieure, et cible les plateformes Win32 et Win64.

Structure du projet :

json_wrapper/
├── SimpleJSON.pas        # Unité principale de la bibliothèque
├── SimpleJSONDemo.dpr    # Projet de démonstration
└── README.md             # Documentation technique

Compilation via la ligne de commande :

dcc32 SimpleJSONDemo.dpr

Étiquettes: Delphi JSON system.json fluent-api object-pascal

Publié le 10 juillet à 17h48