Search code examples
jsondelphidelphi-xe

Rest.JSON with same name parent-child class property


I'm trying to use Rest.JSON in this example below but I'm losting the same name property parent-child class (Items). Just create a new vcl application in Delphi XE and paste this code to see what's happening:

unit Unit1;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Rest.JSON;

type
  TParentItemsClass = class
  strict private
    fID: integer;
    fName: string;
  public
    property ID: integer read fID write fID;
    property Name: string read fName write fName;
  end;

  TParentClass = class
  strict private
    fID: integer;
    fName: string;
    fItems: TParentItemsClass;
  public
    constructor Create;
    property ID: integer read FID write fID;
    property Name: string read FName write fName;
    property Items: TParentItemsClass read FItems write fItems;
  end;

  TChildItemsClass = class(TParentItemsClass)
  strict private
    fSomeField: integer;
  public
    property SomeField: integer read fSomeField write fSomeField;
  end;

  TChildClass = class(TparentClass)
  strict private
    fItems: TChildItemsClass;
  public
    constructor Create;
    property Items: TChildItemsClass read fItems write fItems;

  end;

  TForm1 = class(TForm)
  private
    { Private declarations }
  public
    constructor Create(AOwner: TComponent); override;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TParentClass }


{ TParentClass }

constructor TParentClass.Create;
begin
  fItems:= TParentItemsClass.Create;
end;

{ TChildClass }

constructor TChildClass.Create;
begin
  fItems:= TChildItemsClass.Create;
end;

{ TForm1 }

constructor TForm1.Create(AOwner: TComponent);
var AChild, BChild: TChildClass;
begin
  inherited;
  AChild:= TChildClass.Create;
  AChild.Items.ID:= 1;
  AChild.Items.SomeField:= 2;
  AChild.Items.Name:= 'abc';
  BChild:= TJSON.JsonToObject<TChildClass>(TJSON.ObjectToJsonString(AChild));
  Application.MessageBox(PWideChar(TJSON.ObjectToJsonString(AChild)+#13+#13+TJSON.ObjectToJsonString(BChild)), '', mb_ok);
end;

end.

This results in:


AChild:

{"items":{"someField":2,"iD":1,"name":"abc"},"iD":0,"name":"","items":null}

BChild

{"items":null,"iD":0,"name":"","items":null}

How to avoid this? I need that BChild JSON looks like AChild JSON


Solution

  • Your class TParentClass and TChildClass both have a private field fItems. If you watch the JSON your code outputs closely, you have already posted the answer in your question!

    Look at the value of AChild:

    {
        "items": {
            "someField": 2,
            "iD": 1,
            "name": "abc"
        },
        "iD": 0,
        "name": "",
        "items": null
    }
    

    See how it contains items twice. This is what gets used when you marshal your JSON string back to BChild. And this is certainly not what you want.

    A quick workaround would be renaming your internal field TChildClass.fItems to, for example TChildClass.fItems_.