#1 2015-04-27 07:59:49

Alek
Member
From: Russia
Registered: 2014-07-04
Posts: 44

Can not unserialized nested TObjectList

I tried save instance of object with ObjectToJSON. And it's really ok. But a want to load my file, i get message "not valid". In debug i found, when parser read nested TObjectList = TDevice, it can not detect its.

Try this code.

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, SynCommons, mORMot, Contnrs, StdCtrls;

type

  TSpeed = (s9600,s38400);

  TLine = class;
  TConfig = class;

  TDevice = class(TPersistent)
  strict private
    fParentLine : TLine;
    fName    : string;
    fSpeed   : TSpeed;
    fAdress  : Integer;
  public
    constructor Create(ALine:TLine;AName:string;Adress:Integer);
    property ParentLine : TLine read fParentLine write fParentLine;
  published
    property Name    : string  read fName    write fName;
    property Speed   : TSpeed  read fSpeed   write fSpeed;
    property Adress  : Integer read fAdress  write fAdress;
  end;


  TLine = class(TPersistent)
  strict private
    fParentConfig : TConfig;
    fListDevices : TObjectList;
    fName    : string;
    fComPort : string;
    fIniFile : string;
  public
    constructor Create(AConfig:TConfig;ANameLine,AComPort:string);
    destructor Destroy; override;
    function AddDevice(AName:string):TDevice;

    property ParentConfig : TConfig read fParentConfig write fParentConfig;
  published
    property NameLine  : string  read fName      write fName;
    property ComPort   : string  read fComPort   write fComPort;
    property IniFile   : string  read fIniFile   write fIniFile;

    property ListDevices : TObjectList read fListDevices write fListDevices;
  end;

  TConfig = class(TPersistent)
  private
    fListLines : TObjectList;
  public
    constructor Create;
    destructor Destroy; override;
    function AddLine(AName,AComPort:string):TLine;
    procedure SaveConfig(AFileName:string);
    procedure LoadConfig(AFileName:string);
  published
    property ListLines : TObjectList read fListLines write fListLines;
  end;

  TForm1 = class(TForm)
    btnSave: TButton;
    btnLoad: TButton;
    btnCreate: TButton;
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure btnCreateClick(Sender: TObject);
    procedure btnLoadClick(Sender: TObject);
    procedure btnSaveClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
    Config:TConfig;
  end;

var
  Form1: TForm1;



implementation

{$R *.dfm}

{ TLine }

function TLine.AddDevice(AName: string): TDevice;
begin
  Result:=TDevice.Create(Self, AName, 1);
  fListDevices.Add(Result);
end;

constructor TLine.Create(AConfig:TConfig;ANameLine,AComPort:string);
begin
  fParentConfig:=AConfig;
  fName:=ANameLine;
  fComPort:=AComPort;
  fListDevices:=TObjectList.Create;
end;

destructor TLine.Destroy;
begin
  fListDevices.Free;
  inherited;
end;

{ TConfig }

function TConfig.AddLine(AName,AComPort: string):TLine;
begin
  Result:=TLine.Create(Self,AName,AComPort);
  fListLines.Add(Result);
end;

constructor TConfig.Create;
begin
  inherited;
  fListLines:=TObjectList.Create;
end;

destructor TConfig.Destroy;
begin
  fListLines.Free;
  inherited;
end;

procedure TConfig.LoadConfig(AFileName: string);
var s:RawUTF8;
  isValid: Boolean;
begin
  s:=StringToUTF8(StringFromFile(AFileName));
  JSONToObject(Self,@s[1],isValid);
  if not isValid then ShowMessage('not valid');
end;

procedure TConfig.SaveConfig(AFileName: string);
var
  s: string;
begin
  s:=UTF8ToString(ObjectToJSON(Self,[woDontStoreDefault,woHumanReadable]));
  FileFromString(s,AFileName);
end;

procedure TForm1.btnCreateClick(Sender: TObject);
var Line:TLine; Dev:TDevice;
begin
  Line:=Config.AddLine('MyLine','COM1');
  Line.AddDevice('MyDevice');
end;

procedure TForm1.btnLoadClick(Sender: TObject);
begin
  Config.LoadConfig('test.cnfg');
end;

procedure TForm1.btnSaveClick(Sender: TObject);
begin
  Config.SaveConfig('test.cnfg');
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  Config:=TConfig.Create;
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
  Config.Free;
end;

{ TDevice }

constructor TDevice.Create(ALine: TLine; AName: string;Adress:Integer);
begin
  fParentLine:=ALine;
  fName:=AName;
  fAdress:=Adress;
end;

initialization
  TJSONSerializer.RegisterClassForJSON([TLine, TDevice]);


finalization

Offline

#2 2015-04-27 08:40:35

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

Re: Can not unserialized nested TObjectList

There is no way of knowing which TObject instance is to be created when you read the JSON content.

Try to add woStoreClassName option, and register the corresponding class.
Please check the documentation of JSONToObject().
This is clearly stated AFAIR - see http://synopse.info/files/html/api-1.18 … ONTOOBJECT

Offline

#3 2015-04-27 10:46:09

Alek
Member
From: Russia
Registered: 2014-07-04
Posts: 44

Re: Can not unserialized nested TObjectList

this is my file

{
	"ClassName":"TConfig",
	"ListLines": 
	[{
			"ClassName":"TLine",
			"NameLine": "MyLine",
			"ComPort": "COM1",
			"IniFile": "",
			"ListDevices": 
			[{
					"ClassName":"TDevice",
					"Name": "MyDevice",
					"Speed": "9600",
					"Adress": 1
				}
			]
		}
	]
}

there is field "classname", but it did not help.

The option "woStoreClassName" adds only property "TConfig" to the root object. Other options were earlier.

Offline

#4 2015-04-27 10:48:40

Alek
Member
From: Russia
Registered: 2014-07-04
Posts: 44

Re: Can not unserialized nested TObjectList

I have registred classes in initialization section

  TJSONSerializer.RegisterClassForJSON([TLine, TDevice]);

Offline

#5 2015-04-27 17:21:15

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

Re: Can not unserialized nested TObjectList

... and TConfig?

Offline

#6 2015-04-28 12:37:13

Alek
Member
From: Russia
Registered: 2014-07-04
Posts: 44

Re: Can not unserialized nested TObjectList

It did not solve the problem. Then problem is that function Item := ClassInstanceCreate(ItemClass) doesn't call "create" method TLine object and therefore all of its properties equals nil.

Offline

#7 2015-04-28 13:11:35

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

Re: Can not unserialized nested TObjectList

You should change the class you inherit from.

Use TSynPersistent as parent class, and override its plain Create; virtual; constructor.

Also consider using TPersistentAutoCreateFields or TSynAutoCreateFields if you want the fields class instance to be initialized directly, without even the need to overwrite the constructor.

Offline

#8 2015-04-28 14:02:41

Alek
Member
From: Russia
Registered: 2014-07-04
Posts: 44

Re: Can not unserialized nested TObjectList

i used TSynPersistent and now its all works, though ealier i used TComponent as parent class, but it didn't work.

Thank you.

Offline

Board footer

Powered by FluxBB