I'm having trouble deserializing an object containing a interface field from json using SuperObject (serialization works fine) on DXE2. Consider the following:
ITest = interface(IInterface)
['{9E5623FF-1BC9-4FFA-919D-80C45EE24F38}']
function GetField3() : string;
procedure SetField3(Value: string);
property FField3: string read GetField3 write SetField3;
end;
TTest = class(TInterfacedObject, ITest)
private
FField3: string;
function GetField3() : string;
procedure SetField3(Value: string);
public
property Field3: string read GetField3 write SetField3;
constructor Create(Field3: string);
end;
TMyClass = class(TObject)
public
FField1: string;
FField2: string;
FTest: ITest;
constructor Create(Field1: string; Field2: string; Test: ITest);
end;
// TTest-stuff omitted for brevity.
constructor TMyClass.Create(Field1, Field2: string; Test: ITest);
begin
FField1 := Field1;
FField2 := Field2;
FTest := Test;
end;
var
MyClass: TMyClass;
MyClass2: TMyClass;
JSONObj: ISuperObject;
SuperContext: TSuperRttiContext;
begin
MyClass := TMyClass.Create('Test1', 'Test2', TTest.Create('Test3'));
SuperContext := TSuperRttiContext.Create();
JSONObj := SuperContext.AsJson<TMyClass>(MyClass);
WriteLn(JSONObj.AsString);
MyClass2 := SuperContext.AsType<TMyClass>(JSONObj);
MyClass2.Free();
ReadLn;
end.
When execution gets to TSuperRttiContext.FromJson.FromClass
checking the FTest
-field, the doo-doo hits the propeller in the ceiling (or table mounted, if you prefer that). At this point, Result := FromJson(f.FieldType.Handle, GetFieldDefault(f, obj.AsObject[GetFieldName(f)]), v);
is called, which leads us into the interesting part of the SuperObject.pas code. I'll duplicated it here for brevity.
procedure FromInterface;
const soguid: TGuid = '{4B86A9E3-E094-4E5A-954A-69048B7B6327}';
var
o: ISuperObject;
begin
if CompareMem(@(GetTypeData(TypeInfo).Guid), @soguid, SizeOf(TGUID)) then
begin
if obj <> nil then
TValue.Make(@obj, TypeInfo, Value) else
begin
o := TSuperObject.Create(stNull);
TValue.Make(@o, TypeInfo, Value);
end;
Result := True;
end else
Result := False;
end;
The value assigned to soguid
is that of ISuperObject
, so clearly the two won't match (I'm testing for ITest
, remember?). And so I'm a little lost of what to make of this. Is it illegal to deserialize any object composed of one or more interface fields?
This seems like such a common use case, that I find it hard to believe. I can appreciate the fact that knowing what implementation of a given interface to choose may be non-trivial. Yet, I see from the comment in the preamble, that interfaced objects are supposed to be supported - http://code.google.com/p/superobject/source/browse/trunk/superobject.pas#47.
Sure would be great if anyone have solved this out there. Thanks! :)