You are not logged in.
Pages: 1
If I use [woStoreClassName] when serializing an object which contains a property/field of type TObjectList it correctly serializes to Json as expected using ObjectToJson.
Normally, when deserializing, you would pass in the expected class name (assuming no custom serializer registered) to tell JsonToObject what class to create the objects of.
However, with nested List objects, there's no opportunity to do that as JsonToObject will call (TPropInfo)P^.ClassFromJSON. This in turn will ultimately recurse back into JsonToObject but always passes nil as the class to construct the list objects for. Is there anyway to let it read the class name that is stored in the Json string or am I forced to use a custom serializer with these types of objects?
A simple example:
TMyObj2 = class(TPersistentWithCustomCreate)
private
FTesting: string;
public
constructor Create; override;
published
property Testing: string read FTesting write FTesting;
end;
TMyObject = class(TPersistentWithCustomCreate)
private
FAValue1: string;
FAValue2: string;
FAValue3: Integer;
FMyObj2: TMyObj2;
FNextLevel: TNextLevel;
FMyObj2List: TObjectList;
public
constructor Create; override;
destructor Destroy; override;
function SetCreate(AValue1, AValue2: string; AValue3: Integer): TMyObject;
published
property MyObj2: TMyObj2 read FMyObj2;
property NextLevel: TNextLevel read FNextLevel;
property AValue1: string read FAValue1 write FAValue1;
property AValue2: string read FAValue2 write FAValue2;
property AValue3: Integer read FAValue3 write FAValue3;
property MyObj2List: TObjectList read FMyObj2List;
end;
{ TMyObject }
constructor TMyObject.Create;
begin
FMyObj2 := TMyObj2.Create;
FNextLevel := TNextLevel.Create;
FMyObj2List := TObjectList.Create;
end;
function TMyObject.SetCreate(AValue1, AValue2: string; AValue3: Integer): TMyObject;
begin
FAValue1 := AValue1;
FAValue2 := AValue2;
FAValue3 := AValue3;
Result := Self;
end;
destructor TMyObject.Destroy;
begin
FMyObj2List.Free;
FNextLevel.Free;
FMyObj2.Free;
inherited;
end;
procedure TestmORMot_NestedObjectList;
var
List: TObjectList;
Json: RawUTF8;
Valid: Boolean;
MyObj2: TMyObj2;
begin
List := TObjectList.Create;
try
List.Add(TMyObject.Create.SetCreate('a','b', 1));
List.Add(TMyObject.Create.SetCreate('c','d', 2));
TMyObject(List[0]).MyObj2.Testing := 'Testing 1';
TMyObject(List[1]).MyObj2.Testing := 'Testing 2';
MyObj2 := TMyObj2.Create;
MyObj2.Testing := 'My Obj Item 1';
TMyObject(List[0]).MyObj2List.Add(MyObj2);
MyObj2 := TMyObj2.Create;
MyObj2.Testing := 'My Obj Item 2';
TMyObject(List[0]).MyObj2List.Add(MyObj2);
Json := ObjectToJson(List);
Writeln(Utf8ToString(Json));
finally
List.Free;
end;
Writeln('===================================================');
List := TObjectList.Create;
try
JsonToObject(List, @Json[1], Valid, TMyObject);
if valid then
begin
Writeln('Testing is - ' + TMyObject(List[1]).MyObj2.Testing);
Writeln(List.Count);
end
else
Writeln('Not Valid');
finally
List.Free;
end;
end;
This will result in this Json:
[{"ClassName":"TMyObject","MyObj2":{"ClassName":"TMyObj2","Testing":"Testing 1"},"NextLevel":{"ClassName":"TNextLevel","NextLevelDesc":"","TopLevelDesc":""},"AValue1":"a","AValue2":"b","AValue3":1,"MyObj2List":[{"ClassName":"TMyObj2","Testing":"My Obj Item "},{"ClassName":"TMyObj2","Testing":"My Obj Item 2"}]},{"ClassName":"TMyObject","MyObj2":{"ClassName":"TMyObj2","Testing":"Testing 2"},"NextLevel":"ClassName":"TNextLevel","NextLevelDesc":"","TopLevelDesc":""},"AValue1":"c","AValue2":"d","AValue3":2,"MyObj2List":[]}]
===================================================
But will always return not valid as it doesn't know what class to use in the MyObjList2 field.
Thanks
Offline
As documented, just add
TJSONSerializer.RegisterClassForJSON(TMyObj2);
So that the TObjectList item classnames should be recognized.
The JSONToObject() documentation was pretty clear IMHO:
// - won't handle TObjectList (even if ObjectToJSON is able to serialize
// them) since has now way of knowing the object type to add (TCollection.Add
// is missing), unless: 1. you set the TObjectListItemClass property as expected,
// and provide a TObjectList object, or 2. woStoreClassName option has been
// used at ObjectToJSON() call and the corresponding classes have been previously
// registered by TJSONSerializer.RegisterClassForJSON() (or Classes.RegisterClass)
Offline
Hello,
Is this the case still? I'm trying to serialize a TObjectList but have a hard time understanding this.
Offline
Pages: 1