JSON persistence (VCL.TMSFNCPersistence, VCL.TMSFNCTypes)

Hi,

I'm about to replace a third party JSON library with what is available from TMS to better standardize my code. I've read the good article: TMS Software | Blog
I have a couple of questions related to using the JSON persistence available from VCL.TMSFNCPersistence, VCL.TMSFNCTypes.

I'm using latest version 3.0.0.2 of the FNC Core library

I have this demo class:

  TMyEnum = (AAA, BBB, CCC);

  TDemoClass01 = class(TPersistent)
  private
    FName: string;
    FMyEnum: TMyEnum;
    FB: integer;
    FC: integer;
  published
    property Name: string read FName write FName;
    property A: TMyEnum read FMyEnum write FMyEnum;
    property B: integer read FB write FB;
    property C: integer read FC write FC;
  end;

  //I use the following code to display the JSON
  var lClass := TDemoClass01.Create;
  try
    lClass.FName := 'TMS';
    lClass.A := TMyEnum.AAA;
    lClass.B := 2;
    lClass.C := 3;
    ShowMessage(lClass.ToJSON);
  finally
    lClass.Free;
  end;

The resulting JSON from this class looks like this:

{"$type":"TDemoClass01","A":0,"B":2,"C":3,"Name":"TMS"}

Question #1: Why is the property A displayed as integer in the resulting JSON string when it is an enum?

Question #2: I see there is a TTMSFNCJSONToClassOptions record in the file VCL.TMSFNCPersistence. I assume I can use this to alter the default sorting of elements in the resulting JSON. May I please ask for an example of how to do so?

Question #3: My demo class in this post is inherited from TPersistent, but the base class of my real classes are inherited from TObject. I noticed in the file VCL.TMSFNCPersistence that there is a declaration like: TTMSFNCJSONToClassBaseClass = (cbcNone, cbcPersistent);. Is this something I can use for classes derived from TObject instead of TPersistent? If so, may I plase ask for an example or hint of how to use it?

PS. Maybe you prefer 1 question per post. Sorry for putting in 3 in the same post, but thought it belonged together. I'd be happy to split my post in 3 if you prefer.

Thank you in advance, and if there is any documentation you think I've might have missed please don't hesitate to tell me.

Hi,

  1. An enum value is essentially an Integer, that's why we are storing enum values as Integers. JSON is limited to numbers and strings as values so there is no alternative to store enums.

  2. Sorting of properties cannot be manipulated. The sorting is determined by RTTI looping through properties.

  3. Inheriting from TPersistent is optional, but assures you can publish properties which are mandatory to persist your object. You can inherit from TObject, and keep published properties, but then you'll experience a warning:

[dcc32 Warning] MyUnit.pas(11): W1055 PUBLISHED caused RTTI ($M+) to be added to type 'TMyObject'

For question 2 & 3. TTMSFNCJSONToClass is actually a helper that generates classes and properties based on JSON. What you are doing in the above code snippet is not related this functionality. It's a complete different new class we wrote to assist you in writing Delphi classes to import JSON. Since you already have your class, this functionality is not applicable.

For more info around JSON to object & object to JSON you can read this:

or a series of blog posts:

Thank you Pieter, much appreciated.

I might have to take a close look at the REST.Json already in Delphi as I'm dependent on enum's being displayed as strings. Some of my classes are saved in database in string fields as Json, and then picked up by secondary (None Delphi) systems that rely on the text representation.

Regards,
Leif Eirik

Hi,

You can manipulate how properties are written and in which format they are written. Below is a complete sample to capture the property A, override the default write operation and write your own property name & data, being the enum value as a string. Note that when you are writing your data to JSON, and you want to convert it back to your object, you'll have to do the reverse as well with the OnCustomReadProperty.

unit Unit23;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, VCL.TMSFNCJSONWriter;

type
  TForm23 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure DoCustomWriteProperty(AObject: TObject; APropertyName: string;
      APropertyKind: TTypeKind; AWriter: TTMSFNCJSONWriter;
      var ACanWrite: Boolean);
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyEnum = (AAA, BBB, CCC);

  TDemoClass01 = class(TPersistent)
  private
    FName: string;
    FMyEnum: TMyEnum;
    FB: integer;
    FC: integer;
  published
    property Name: string read FName write FName;
    property A: TMyEnum read FMyEnum write FMyEnum;
    property B: integer read FB write FB;
    property C: integer read FC write FC;
  end;

var
  Form23: TForm23;

implementation

{$R *.dfm}

uses
  VCL.TMSFNCTypes, VCL.TMSFNCPersistence;

procedure TForm23.DoCustomWriteProperty(AObject: TObject; APropertyName: string; APropertyKind: TTypeKind; AWriter: TTMSFNCJSONWriter; var ACanWrite: Boolean);
begin
  if AObject is TDemoClass01 then
  begin
    if APropertyName = 'A' then
    begin
      ACanWrite := False;
      AWriter.WriteName('A');
      AWriter.WriteString(TTMSFNCPersistence.GetEnumName(TypeInfo(TMyEnum), Integer((AObject as TDemoClass01).A)));
    end;
  end;
end;

procedure TForm23.Button1Click(Sender: TObject);
var
  co: TTMSFNCWriterCustomWritePropertyEvent;
begin
  //I use the following code to display the JSON
  var lClass := TDemoClass01.Create;
  try
    lClass.FName := 'TMS';
    lClass.A := TMyEnum.AAA;
    lClass.B := 2;
    lClass.C := 3;

    co := TTMSFNCPersistence.OnCustomWriteProperty;
    TTMSFNCPersistence.OnCustomWriteProperty := DoCustomWriteProperty;
    lClass.Log;
    TTMSFNCPersistence.OnCustomWriteProperty := co;
  finally
    lClass.Free;
  end;
end;

end.

Debug Output: {"$type":"TDemoClass01","A":"AAA","B":2,"C":3,"Name":"TMS"} Process Project23.exe (12356)

Ahh, nice!
I did actually notice the OnCustomWriteProperty in your source, but didn't want to ask at first since I already put 3 questions in my original request :slight_smile:

Anyway, I can absolutely work with your suggestion. I addition I do not require to convert back from JSON to object, but thanks for mentioning it.

I'll give your code a try right away.

1 Like