Blog

All Blog Posts  |  Next Post  |  Previous Post

Diving deeper: JSON persistence, part 3/4: Generics

Monday, August 8, 2022

TMS Software Delphi  Components

Generics

The previous blog post explained how to deal with collections. This blog post will use and transform the TPersonRelations collection to a TObjectList<TPersonRelation> generic type list.

TPersonRelation = class(TPersistent)
private
  FName: string;
  FDescription: string;
public
  procedure Assign(Source: TPersistent); override;
published
  property Name: string read FName write FName;
  property Description: string read FDescription write FDescription;
end;

TPersonRelations = TObjectList<TPersonRelation>;
The definition of our JSON sample code remains identical. The TPersonRelations will represent a JSON array of objects.

const
  jsonSample =
    '{' +
      '"$type":"TPerson",' +
      '"address":{' +
        '"$type":"TPersonAddress",' +
        '"addressLocality":"Colorado Springs",' +
        '"addressRegion":"CO",' +
        '"postalCode":"80840",' +
        '"streetAddress":"100 Main Street"' +
      '},' +
      '"colleague":[' +
        '"http://www.example.com/JohnColleague.html",' +
        '"http://www.example.com/JameColleague.html"' +
      '],' +
      '"email":"info@example.com",' +
      '"jobTitle":"Research Assistant",' +
      '"name":"Jane Doe",' +
      '"birthDate":"1979-10-12",' +
      '"gender":"female",' +
      '"nationality":"Albanian",' +
      '"relations": ['+
        '{'+
          '"$type":"TPersonRelation",' +
          '"Description": "Brother",'+
          '"Name": "John Doe"'+
        '},'+
        '{'+
          '"$type":"TPersonRelation",' +
          '"Description": "Mother",'+
          '"Name": "Mia Reyes"'+
        '}'+
      '],'+
      '"telephone":"(123) 456-6789",' +
      '"url":"http://www.example.com"' +
    '}';

Saving a generic list

Saving an object including a generic list is as simple as using the class helpers, in the same way as you would do in the previous blog post related to collections. The generic list (or object list), will be transformed in a JSON array of objects, including the class type of the TPersonRelation object. Instead of a TCollectionItem, this is now a TPersistent class.

var
  p: TPerson;
begin
  p := TPerson.Create;
  try
    p.Log;
  finally
    p.Free;
  end;
end;

The output of this statement is

{
  "$type": "TPerson",
  "Address": {
    "$type": "TPersonAddress",
    "AddressLocality": "Colorado Springs",
    "AddressRegion": "CO",
    "PostalCode": "80840",
    "StreetAddress": "100 Main Street"
  },
  "BirthDate": "1979-10-12",
  "Colleagues": [],
  "Email": "info@example.com",
  "Gender": "female",
  "JobTitle": "Research Assistant",
  "Name": "Jane Doe",
  "Nationality": "Albanian",
  "Relations": [
    {
      "$type": "TPersonRelation",
      "Description": "Brother",
      "Name": "John Doe"
    },
    {
      "$type": "TPersonRelation",
      "Description": "Mother",
      "Name": "Mia Reyes"
    }
  ],
  "Telephone": "(123) 456-6789",
  "URL": "http://www.example.com"
}

Loading a generic list

To understand how to load JSON data containing an array which will be mapped onto a generic list, please head over to the previous blog post explaining which interfaces are required to handle and load JSON with and without the "$type" properties. The loading mechanism for a generic list is exactly the same as with a TCollection.

Working with a TDictionary<K, T>

TDictionary<K, T> is supported, but the key type is restricted to a string. Let's take a look at the following example.

TMyObject = class(TPersistent)
private
  FMyProperty: string;
published
  property MyProperty: string read FMyProperty write FMyProperty;
end;

TMyDictionary = TObjectDictionary<string, TMyObject>;

We'll add 2 objects respectively in key 1 & 2.

var
  d: TMyDictionary;
  o: TMyObject;
begin
  d := TMyDictionary.Create;

  try
    o := TMyObject.Create;
    o.MyProperty := 'Property Value 1';
    d.Add('1', o);

    o := TMyObject.Create;
    o.MyProperty := 'Property Value 2';
    d.Add('2', o);

    d.Log;
  finally
    d.Free;
  end;

When executing this code, it generates the following JSON:

[
  {
    "2": {
      "$type": "TMyObject",
      "MyProperty": "Property Value 2"
    }
  },
  {
    "1": {
      "$type": "TMyObject",
      "MyProperty": "Property Value 1"
    }
  }
]

Supported generic types

Not all types are supported when persisting to JSON. Below is a list of supported types that can be used when converting your object to JSON or vice versa.

  • TList<TObject>, or TObjectList<TObject>
  • TList<string>
  • TList<Integer>
  • TList<Double>

In the following sample, we'll demonstrates how to use and persist a generic TList<Integer>.

TMyIntegerList = TList<Integer>;
var
  l: TMyIntegerList;
begin
  try
    l := TMyIntegerList.Create;
    l.Add(50);
    l.Add(6);
    l.Add(978);
    l.Add(20);
    l.Log;
  finally
    l.Free;
  end;
end;
Executing the code will show the result in JSON, which basically translates to an array of integer values.

[
  50,
  6,
  978,
  20
]

Feedback

Next up will be how to use the undo/redo manager, so stay tuned for more to come! As always, please leave a comment or if you have any questions, don't hesitate to ask us!



Pieter Scheldeman




This blog post has not received any comments yet.



Add a new comment

You will receive a confirmation mail with a link to validate your comment, please use a valid email address.
All fields are required.



All Blog Posts  |  Next Post  |  Previous Post