#1 2014-04-22 05:30:37

avista
Member
Registered: 2014-01-06
Posts: 63

Problem with JSON Serialization and Nested Objects

I'm sure this is simple, but I can't seem to get this to work:

type
  TAddress = class
  private
    FStreet: string;
    FCity: string;
    FZipCode: string;
    FCountry: string;
  published
    property Street: string read FStreet write FStreet;
    property City: string read FCity write FCity;
    property ZipCode: string read FZipCode write FZipCode;
    property Country: string read FCountry write FCountry;
  end;

  TContact = class
  private
    FId: Integer;
    FFirstName: string;
    FLastLame: string;
    FAddress: TAddress;
    FLastName: string;
  public
    constructor Create;
    destructor Destroy; override;
  published
    property Id: Integer read FId write FId;
    property FirstName: string read FFirstName write FFirstName;
    property LastName: string read FLastName write FLastName;
    property Address: TAddress read FAddress write FAddress;
  end;

{ TContact }

constructor TContact.Create;
begin
  inherited;
  FAddress := TAddress.Create;
end;

destructor TContact.Destroy;
begin
  FAddress.Free;
  inherited;
end;

procedure TForm1.btnTestClick(Sender: TObject);
var
  C1, C2: TContact;
  Json: RawUTF8;
  JsonPtr: PUTF8Char;
  IsValidJson: Boolean;
begin
  TJSONSerializer.RegisterClassForJSON([TContact, TAddress]);
  // C1
  C1 := TContact.Create;
  C1.FirstName := 'Joe';
  Json := ObjectToJson(C1, [woStoreClassName, woHumanReadable]);
  C1.Free;
  // C2
  Memo.Lines.Add(Json);
  JsonPtr := @Json[1];
  C2 := TContact(JSONToNewObject(JsonPtr, IsValidJson, [j2oIgnoreUnknownProperty]));
  Assert(IsValidJson); // <-------- ASSERTION FAILS HERE
  C2.Free;
end;

The assertion in the test function above fails, but I don't see why, considering I've registered both classes.

If I comment out the 'Address' property in TContact, everything works fine.

Thanks

Offline

#2 2014-04-22 07:14:23

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Problem with JSON Serialization and Nested Objects

I suppose that, as stated by the documentation, your classes need to have RTTI enabled.
Either inherit from TPersistent, either add {$M+} ...  {$M-} to the class definitions.

What is the JSON content?
Are you using the latest 1.18 revision?

Offline

#3 2014-04-22 17:24:54

avista
Member
Registered: 2014-01-06
Posts: 63

Re: Problem with JSON Serialization and Nested Objects

Here is a complete test program, but it still fails even after using M+ and descending from TPersistent.  I'm using Delphi XE 2 Update 4 Hotfix 1, along with the nightly Mormot build from April 20, 2014.

{$M+}
program JsonTest;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  System.SysUtils, Classes, SynCommons, Mormot;

type
  TAddress = class(TPersistent)
  private
    FStreet: string;
    FCity: string;
    FZipCode: string;
    FCountry: string;
  published
    property Street: string read FStreet write FStreet;
    property City: string read FCity write FCity;
    property ZipCode: string read FZipCode write FZipCode;
    property Country: string read FCountry write FCountry;
  end;

  TContact = class(TPersistent)
  private
    FId: Integer;
    FFirstName: string;
    FLastName: string;
    FAddress: TAddress;
  public
    constructor Create;
    destructor Destroy; override;
  published
    property Id: Integer read FId write FId;
    property FirstName: string read FFirstName write FFirstName;
    property LastName: string read FLastName write FLastName;
    property Address: TAddress read FAddress write FAddress;
  end;

{ TContact }

constructor TContact.Create;
begin
  inherited;
  FAddress := TAddress.Create;
end;

destructor TContact.Destroy;
begin
  FAddress.Free;
  inherited;
end;

var
  C1, C2: TContact;
  Json: RawUTF8;
  JsonPtr: PUTF8Char;
  IsValidJson: Boolean;
  Ch: Char;
begin
  try
    TJSONSerializer.RegisterClassForJSON([TContact, TAddress]);
    // C1
    C1 := TContact.Create;
    C1.FirstName := 'Joe';
    C1.LastName := 'Smith';
    C1.Address.Street := '1234 Main St.';
    Json := ObjectToJson(C1, [woStoreClassName, woHumanReadable]);
    Writeln('=== C1 ===');
    Writeln(Json);
    C1.Free;
    Writeln;
    Writeln('Press ENTER to continue...');
    Readln;
    // C2
    JsonPtr := @Json[1];
    C2 := TContact(JSONToNewObject(JsonPtr, IsValidJson, [j2oIgnoreUnknownProperty]));
    Assert(IsValidJson);
    Writeln('=== C2 ===');
    Writeln(C2.FirstName);
    Writeln(C2.LastName);
    Writeln(C2.Address.Street);
    C2.Free;
    Writeln;
    Writeln('Press ENTER to continue...');
    Readln;
  except
    on E: Exception do
      Writeln(E.ClassName, ': ', E.Message);
  end;
end.

Offline

#4 2014-04-22 19:36:44

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,182
Website

Re: Problem with JSON Serialization and Nested Objects

As stated by the documentation, if you use:

  TContact = class(TPersistentWithCustomCreate)
  ...
    constructor Create; override;

It should work as expected.

Offline

#5 2014-04-22 21:18:37

avista
Member
Registered: 2014-01-06
Posts: 63

Re: Problem with JSON Serialization and Nested Objects

Thanks, I needed to inherit from TPersistentWithCustomCreate *AND* specify the override directive in TContact.Create(). smile

However, regarding the documentation, perhaps I don't have the latest?

Synopse mORMot Framework
Software Architecture Design 1.18
Date: November 12, 2013

The only places I see TPersistentWithCustomCreate referenced are pages: 801, 803, 902

There is no mention of this in the usage section in "10.1.6. TObject serialization"

Offline

Board footer

Powered by FluxBB