IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Delphi Discussion :

Serialisation d'objets : ignorer les propriétés héritées


Sujet :

Delphi

  1. #1
    Invité
    Invité(e)
    Par défaut Serialisation d'objets : ignorer les propriétés héritées
    Bonjour,

    J'essaie d'apprendre à sérialiser des objets avec Delphi 10.3.3 Rio en utilisant les unités : REST.JsonReflect et REST.JSON.Types

    J'ai écrit cette classe :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    TContainer: class(TGraphicControl)
    private
      [JSONMarshalledAttribute(False)] // Test to hide a property : works
      FObj: TObject;
      FId: Integer;
      FContainerName: string;
      [JsonName('Type')] // Test to customize the property name : works
      FContainerType: string;
    public
      property Id: Integer read FId write FId;
      property ContainerName: string read FContainerName write FContainerName;
      property ContainerType: string read FContainerType write FContainerType;
    end;
    Ensuite pour sérialiser, je fais de cette manière :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
    var
      m: TJSONMarshal;  
      JSONString: String;
      Container: TContainer;
    begin
      Container:= TContainer.Create(nil);
      Container.FId := 12;
      Container.FContainerName := 'Container001';
      Container.FContainerType := 'TYPE_005';
     
      JSONString := m.Marshal(Container).Format;
    Mon code fonctionne lorsque ma classe n'hérite d'aucune autre classe, si je la déclare comme ça :

    Mais lorsque je la déclare comme au dessus :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    TContainer: class(TGraphicControl)
    J'ai une stack overflow exception. Je pense qu'elle est liée à l'héritage. Ma question est donc, est-il possible de ne pas tenir compte des propriétés héritées lors de la sérialisation de sorte que la variable JSONString ressemble à ça :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    {
        "id": 7,
        "containerName": "Container001",
        "Type": "TYPE_005"
    }
    Merci d'avance pour votre aide.

    [EDIT]
    J'ai trouvé cette piste, avec la librairie Newtonsoft.Json en .NET, en ajoutant cette annotation à la classe :
    [JsonObject(MemberSerialization.OptIn)].

    Elle permet de ne sérialiser que les propriétés annotées avec [JsonProperty]. Mais je ne trouve aucun moyen pour le moment de réaliser la même chose avec Delphi.
    Dernière modification par Invité ; 21/01/2021 à 12h06.

  2. #2
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    alors ça fait longtemps que je n'ai pas regardé la sérialisation JSON de Delphi car j'ai depuis longtemps opté pour mon propre code, sous XE8 les références circulaires faisaient planter la sérialisation.

    maintenant, et indépendamment de l'implémentation utilisée, j'ai pris l'habitude de placer les données à sérialiser dans un sous ensemble

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
     
    type
      TContainerData = record
      private
        [JSONMarshalledAttribute(False)] // Test to hide a property : works
        FObj: TObject;
        FId: Integer;
        FContainerName: string;
        [JsonName('Type')] // Test to customize the property name : works
        FContainerType: string;
      public
        property Id: Integer read FId write FId;
        property ContainerName: string read FContainerName write FContainerName;
        property ContainerType: string read FContainerType write FContainerType;
      end;
     
     
      TContainer: class(TGraphicControl)
       Data: TContainerData;
      end;
    en sérialisant le membre Data (qui peut aussi être une classe) tu évites les problèmes d'héritages
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 429
    Points : 24 794
    Points
    24 794
    Par défaut
    Sinon redéfinir soit propre TJSONInterceptor semble pas des plus facile pour généraliser la serialization que des membres de la classe finale hors de membres du Ancestor : Copier un objet dans un enfant
    Tu peux définir une méthode via RegisterConverter modifier le comportement la fonction Marshal ensuite

    Citation Envoyé par Paul TOTH Voir le message
    en sérialisant le membre Data (qui peut aussi être une classe) tu évites les problèmes d'héritages
    Je pratique ainsi pour simplifier mes fonctions Assign

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
      TConfigVersionningSupports = class(TObject)
      private
        type
          TDataVersion = record
            VersionLocalExists: Boolean;
            VersionLocalNotEmpty: Boolean;
            VersionLocalRequired: Boolean;
            VersionArchiveExists: Boolean;
            VersionArchiveReleaseExists: Boolean;
            VersionArchiveAuthorExists: Boolean;
            VersionArchiveAuthorDataLen: Integer;
            VersionArchiveCommentExists: Boolean;
            VersionArchiveCommentDataLen: Integer;
          end;
      strict private
        FTableType: TConfigTableType;
        FData: TDataVersion;
      private
        procedure LoadFromContext(AContext: TConfigContext);
      public
        constructor Create(); overload;
        constructor Create(ATableType: TConfigTableType); overload;
     
        procedure Clear();
        procedure Assign(ASource: TConfigVersionningSupports);
     
        property VersionLocalExists: Boolean read FData.VersionLocalExists;
        property VersionLocalNotEmpty: Boolean read FData.VersionLocalNotEmpty;
        property VersionLocalRequired: Boolean read FData.VersionLocalRequired;
        property VersionArchiveExists: Boolean read FData.VersionArchiveExists;
        property VersionArchiveReleaseExists: Boolean read FData.VersionArchiveReleaseExists;
        property VersionArchiveAuthorExists: Boolean read FData.VersionArchiveAuthorExists;
        property VersionArchiveAuthorDataLen: Integer read FData.VersionArchiveAuthorDataLen;
        property VersionArchiveCommentExists: Boolean read FData.VersionArchiveCommentExists;
        property VersionArchiveCommentDataLen: Integer read FData.VersionArchiveCommentDataLen;
      end;
     
    ...
     
    { TConfigVersionningSupports }
     
    //------------------------------------------------------------------------------
    procedure TConfigVersionningSupports.Assign(ASource: TConfigVersionningSupports);
    begin
      Self.FTableType := ASource.FTableType;
      Move(ASource.FData, Self.FData, SizeOf(FData));
    end;
     
    //------------------------------------------------------------------------------
    procedure TConfigVersionningSupports.Clear();
    begin
      FillChar(FData, SizeOf(FData), 0);
    end;
     
    ...
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

  4. #4
    Invité
    Invité(e)
    Par défaut
    Merci ShaiLeTroll et Paul pour vos réponses, je n'avais pas pensé à cette approche.

  5. #5
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 54
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 430
    Points
    28 430
    Par défaut
    Citation Envoyé par ShaiLeTroll Voir le message
    Sinon redéfinir soit propre TJSONInterceptor semble pas des plus facile pour généraliser la serialization que des membres de la classe finale hors de membres du Ancestor : Copier un objet dans un enfant
    Tu peux définir une méthode via RegisterConverter modifier le comportement la fonction Marshal ensuite



    Je pratique ainsi pour simplifier mes fonctions Assign

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
      TConfigVersionningSupports = class(TObject)
      private
        type
          TDataVersion = record
            VersionLocalExists: Boolean;
            VersionLocalNotEmpty: Boolean;
            VersionLocalRequired: Boolean;
            VersionArchiveExists: Boolean;
            VersionArchiveReleaseExists: Boolean;
            VersionArchiveAuthorExists: Boolean;
            VersionArchiveAuthorDataLen: Integer;
            VersionArchiveCommentExists: Boolean;
            VersionArchiveCommentDataLen: Integer;
          end;
    ...
    //------------------------------------------------------------------------------
    procedure TConfigVersionningSupports.Assign(ASource: TConfigVersionningSupports);
    begin
      Self.FTableType := ASource.FTableType;
      Move(ASource.FData, Self.FData, SizeOf(FData));
    end;
     
    //------------------------------------------------------------------------------
    procedure TConfigVersionningSupports.Clear();
    begin
      FillChar(FData, SizeOf(FData), 0);
    end;
     
    ...
    alors je suppose que tu le sais, mais ce n'est pas explicite dans ton exemple, si FData contient des types dynamiques (string et array par exemple) ce n'est pas la bonne approche
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    procedure TConfigVersionningSupports.Assign(ASource: TConfigVersionningSupports);
    begin
      Self.FTableType := ASource.FTableType;
      Self.Data := ASource.FData; // Delphi s'occupe de tout !
    end;
     
    //------------------------------------------------------------------------------
    procedure TConfigVersionningSupports.Clear();
    begin
      Finalize(FData); // nécessaire pour supprimer les types dynamiques
      FillChar(FData, SizeOf(FData), 0); // pas de soucis pour effacer tout maintenant
    end;
    Developpez.com: Mes articles, forum FlashPascal
    Entreprise: Execute SARL
    Le Store Excute Store

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 429
    Points : 24 794
    Points
    24 794
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    alors je suppose que tu le sais, mais ce n'est pas explicite dans ton exemple, si FData contient des types dynamiques (string et array par exemple) ce n'est pas la bonne approche
    Oui je ne le fais qu'avec des types finis, si j'ai des pointeurs\références, eux même appels si je l'ai codé ou si ça existe en standard le peur propre Assign en cascade, au pire un bon vieux Copy
    Aide via F1 - FAQ - Guide du développeur Delphi devant un problème - Pensez-y !
    Attention Troll Méchant !
    "Quand un homme a faim, mieux vaut lui apprendre à pêcher que de lui donner un poisson" Confucius
    Mieux vaut se taire et paraître idiot, Que l'ouvrir et de le confirmer !
    L'ignorance n'excuse pas la médiocrité !

    L'expérience, c'est le nom que chacun donne à ses erreurs. (Oscar Wilde)
    Il faut avoir le courage de se tromper et d'apprendre de ses erreurs

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 04/04/2013, 13h45
  2. Lister les propriétés d'un objet
    Par DWade dans le forum VB 6 et antérieur
    Réponses: 2
    Dernier message: 14/10/2006, 13h09
  3. [Zope] Changer les propriétés d'un objet
    Par senacle dans le forum Zope
    Réponses: 1
    Dernier message: 27/09/2006, 12h32
  4. [Débutant] Initialiser les propriétés de tous les objets d'une ArrayList
    Par Tententai dans le forum API standards et tierces
    Réponses: 5
    Dernier message: 23/05/2006, 21h24
  5. Réponses: 1
    Dernier message: 20/02/2006, 11h59

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo