Skip to content

The Delphi Json Mapper Record is a native RTL technique from Delphi 11 Alexandria generating units for the record, which allows dynamic conversion between JSON structures and records.

License

Notifications You must be signed in to change notification settings

luis-portfolio/Delphi-JsonMapper-s-Record

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Delphi 11.3 Alexandria Json Mapper's between Record

The Delphi Json Mapper Record is a native RTL technique from Delphi 11 Alexandria generating units for the record, which allows dynamic conversion between JSON structures and records.

📌 Main Features:

    ✅ Dynamic JSON Mapping: Allows for automatic parsing and generation of records from arbitrary JSONs, without having to manually define each field.

    ✅ Bidirectional Conversion: Provides methods to serialize and deserialize JSONs to records using TJSONMarshal and TJSONUnMarshal.

    ✅ Support for Different JSON Types: Recognizes various types such as jtObject, jtArray, jtString, jtNumber, jtDate, jtDateTime, etc.

    ✅ Delphi Code Generation: Provides methods to generate Delphi source code with mapped records, facilitating integration into projects.

    ✅ Customization by Attributes: Can use [JSONReflect] to control the mapping of specific fields when necessary.

    ✅ Use of RTTI: Dynamic parsing is done through RTTI, allowing access and manipulation of types at runtime.

Inout a JSON exiting Record unit

Sample of the uses unit generated MyMappedRecordEntity

uses
  System.SysUtils, System.Classes, System.JSON, JsonMapperAdapter, MyMappedRecordEntity;

procedure TestJsonMapper;
var
  JsonString: string;
  MappedRecord: TMyMappedRecord;
  I: Integer;
begin
  // Input JSON
  JsonString := 
      ' {                                                             ' +
      '     "address": { "city": "Wonderland", "street": "Main St" }, ' +
      '     "age": 30,                                                ' +
      '     "friends": [                                              ' +
      '         { "age": 25, "name": "Bob"     },                     ' +
      '         { "age": 28, "name": "Charlie" }                      ' +
      '     ],                                                        ' +
      '     "hobbies": [                                              ' +
      '         "Reading",                                            ' +
      '         "Traveling",                                          ' +
      '         "Coding"                                              ' +
      '     ],                                                        ' +
      '     "name": "Alice"                                           ' +
      ' }                                                             ' ;

  // Creates the mapper and generates the record
  if JsonMapperAdapter.Mapper
            .JsonString(JsonString)
            .RootRecordName('TMyMappedRecord')
            .UnitName('MyMappedRecordEntity')
            .SaveToFile then
    Writeln('Record generated successfully!');

  // Load JSON into registry
  MappedRecord := TMyMappedRecord.Create(JsonString);

  // Displays mapped record data
  Writeln('Nome: ', MappedRecord.Name);
  Writeln('Idade: ', MappedRecord.Age);
  Writeln('Endereço: ', MappedRecord.Address.Street, ', ', MappedRecord.Address.City);

  Writeln('Hobbies:');
  for I := 0 to High(MappedRecord.Hobbies) do
    Writeln('  - ', MappedRecord.Hobbies[I]);

  Writeln('Amigos:');
  for I := 0 to High(MappedRecord.Friends) do
    Writeln(Format('  - Name: %s | Age: %.0f', [MappedRecord.Friends[I].Name, MappedRecord.Friends[I].Age]));

  // Serialize the record back to JSON
  Writeln('Generated JSON: ');
  Writeln(MappedRecord.StringiFy);
end;

Sample JSON input

{
  "name": "Alice",
  "age": 30,
  "hobbies": ["Reading", "Traveling", "Coding"],
  "address": {
    "street": "Main St",
    "city": "Wonderland"
  },
  "friends": [
    { "name": "Bob", "age": 25 },
    { "name": "Charlie", "age": 28 }
  ]
}

Unit produced MyMappedRecordEntity.pas

unit MyMappedRecordEntity;

{
 ************************************************************************************ 
 *  Generated By: EntityFromJson - 1.0.0.0                                          * 
 *  Project link: https://github.com/luis-portfolio/Delphi-JsonMapper-s-Record.git  * 
 *  Generated On: 2025-03-01 22:01:44                                               * 
 ************************************************************************************ 
 *  Created By  : Luis Caldas - 2025                                                * 
 *  WebSite     : http://app.qbits.pl/LuisCaldas                                    * 
 ************************************************************************************ 
}

interface

uses Generics.Collections, System.JSON.Serializers;

type
  TFriends = record
    [JsonNameAttribute('name')]
    Name: String;
    [JsonNameAttribute('age')]
    Age: Extended;
  end;

  TAddress = record
    [JsonNameAttribute('street')]
    Street: String;
    [JsonNameAttribute('city')]
    City: String;
  end;

  [JsonSerializeAttribute(TJsonMemberSerialization.Fields)]
  TMyMappedRecord = record
    [JsonNameAttribute('name')]
    Name: String;
    [JsonNameAttribute('age')]
    Age: Extended;
    [JsonNameAttribute('hobbies')]
    Hobbies: TArray<String>;
    [JsonNameAttribute('address')]
    Address: TAddress;
    [JsonNameAttribute('friends')]
    Friends: TArray<TFriends>;

    constructor Create(const aJson: string);
    function StringiFy: string;

    procedure HobbiesSize(const aValue: integer);
    procedure FriendsSize(const aValue: integer);
  end;

implementation

{ TMyMappedRecord }

constructor TMyMappedRecord.Create(const aJson: string);
begin
  with TJsonSerializer.Create do
  try
    Populate<TMyMappedRecord>(aJson, Self);
  finally
    Free;
  end;
end;

function TMyMappedRecord.StringiFy: string;
begin
  with TJsonSerializer.Create do
  try
    Result := Serialize<TMyMappedRecord>(Self);
  finally
    Free;
  end;
end;

procedure TMyMappedRecord.HobbiesSize(const aValue: integer);
begin
  SetLength(Hobbies, aValue);
end;

procedure TMyMappedRecord.FriendsSize(const aValue: integer);
begin
  SetLength(Friends, aValue);
end;

end.

Sample of the test to class Mapper TJsonMapperAdapter

program of test use DUnitX

program TestJsonMapper;

uses
  DUnitX.TestFramework,
  DUnitX.Loggers.Console,
  DUnitX.Loggers.XML.NUnit,
  DUnitX.TestRunner,
  System.SysUtils;

{$APPTYPE CONSOLE}

begin
  ReportMemoryLeaksOnShutdown := True;
  DUnitX.Loggers.Console.TDUnitXConsoleLogger.SetupLogging;
  DUnitX.TestRunner.RunRegisteredTests;
end.

Unit of the test

unit TestMyMappedRecord;

interface

uses
  DUnitX.TestFramework, MyMappedRecordEntity, System.SysUtils;

type
  [TestFixture]
  TTestMyMappedRecord = class
  private
    FJsonString: string;
    FRecord: TMyMappedRecord;
  public
    [Setup]
    procedure Setup;

    [TearDown]
    procedure TearDown;

    [Test]
    procedure TestLoadFromJson;

    [Test]
    procedure TestStringiFy;
  end;

implementation

{ TTestMyMappedRecord }

procedure TTestMyMappedRecord.Setup;
begin
  FJsonString := 
      ' {                                                             ' +
      '     "address": { "city": "Wonderland", "street": "Main St" }, ' +
      '     "age": 30,                                                ' +
      '     "friends": [                                              ' +
      '         { "age": 25, "name": "Bob"     },                     ' +
      '         { "age": 28, "name": "Charlie" }                      ' +
      '     ],                                                        ' +
      '     "hobbies": [                                              ' +
      '         "Reading",                                            ' +
      '         "Traveling",                                          ' +
      '         "Coding"                                              ' +
      '     ],                                                        ' +
      '     "name": "Alice"                                           ' +
      ' }                                                             ' ;
end;

procedure TTestMyMappedRecord.TearDown;
begin
end;

procedure TTestMyMappedRecord.TestLoadFromJson;
begin
  FRecord := TMyMappedRecord.Create(FJsonString);

  Assert.AreEqual('Alice', FRecord.Name);
  Assert.AreEqual(30.0, FRecord.Age, 0.1);
  Assert.AreEqual('Main St', FRecord.Address.Street);
  Assert.AreEqual('Wonderland', FRecord.Address.City);

  Assert.AreEqual(3, Length(FRecord.Hobbies));
  Assert.AreEqual('Reading', FRecord.Hobbies[0]);
  Assert.AreEqual('Traveling', FRecord.Hobbies[1]);
  Assert.AreEqual('Coding', FRecord.Hobbies[2]);

  Assert.AreEqual(2, Length(FRecord.Friends));
  Assert.AreEqual('Bob', FRecord.Friends[0].Name);
  Assert.AreEqual(25.0, FRecord.Friends[0].Age, 0.1);
  Assert.AreEqual('Charlie', FRecord.Friends[1].Name);
  Assert.AreEqual(28.0, FRecord.Friends[1].Age, 0.1);
end;

procedure TTestMyMappedRecord.TestStringiFy;
var
  OutputJson: string;
begin
  FRecord := TMyMappedRecord.Create(FJsonString);
  OutputJson := FRecord.StringiFy;

  Assert.IsTrue(OutputJson.Contains('"name":"Alice"'));
  Assert.IsTrue(OutputJson.Contains('"age":30'));
  Assert.IsTrue(OutputJson.Contains('"street":"Main St"'));
  Assert.IsTrue(OutputJson.Contains('"city":"Wonderland"'));
  Assert.IsTrue(OutputJson.Contains('"name":"Bob"'));
  Assert.IsTrue(OutputJson.Contains('"name":"Charlie"'));
end;

initialization
  TDUnitX.RegisterTestFixture(TTestMyMappedRecord);

end.

About

The Delphi Json Mapper Record is a native RTL technique from Delphi 11 Alexandria generating units for the record, which allows dynamic conversion between JSON structures and records.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages