I have an interface IList<T>
(from Spring.Collections
) that I want to deserialize with MVCFrameWork. It does not work, because in the code we have a function IsWrap()
that looks if the methods Add()
and Clear()
exist, but the RTTI for IList
does not include those methods.
Some code:
TPerson = class (TInterfacedObject)
private
fLastName: String;
fFirstName: String;
public
property FirstName: String read fFirstName write fFirstName;
property LastName: String read fLastName write fLastName;
end;
implementation
uses
Generics.Collections,
Spring.Collections,
MVCFramework.Serializer.Intf,
MVCFramework.Serializer.JsonDataObjects;
procedure TSerializerTest.JsonToCollection;
begin
var strJson: string := '[{"FirstName": "Ricardo", "LastName": "The killer" }, {"FirstName": "Zorro", "LastName": "Z-Man" }]';
var oPersons : IList<TPerson> := TCollections.CreateObjectList<TPerson> ;
// var oPersons : TList<TPerson> := TList<TPerson>.Create ;
// var oPersons : TObjectList<TPerson> := TObjectList<TPerson>.Create() ;
var lSerializer: IMVCSerializer := TMVCJsonDataObjectsSerializer.Create;
lSerializer.DeserializeCollection(strJson, oPersons, TPerson);
Assert.AreEqual(oPersons[0].FirstName , 'Ricardo');
Assert.AreEqual(oPersons[1].FirstName , 'Zorro');
end;
TList<TPerson>
and TObjectList<TPerson>
work.
IList<TPerson>
does not work, because we can not find the methods Add()
and Clear()
with the RTTI.
procedure TSerializerTest.CheckAddAndClearRTTI;
var
ObjectType: TRttiType;
FContext: TRttiContext;
begin
var oPersons : IList<TPerson> := TCollections.CreateObjectList<TPerson> ;
//METHODE ADD AND CLEAR EXIST
oPersons.Add(TPerson.Create);
oPersons.Clear;
ObjectType := FContext.GetType(oPersons.AsObject.ClassInfo);
if (ObjectType.GetMethod('Add') <> nil) and (ObjectType.GetMethod('Clear') <> nil) then
begin
ShowMessage('Is List'); // DOES NOT GET HERE, WHY
end;
end;
I am assuming that you are using Spring4D 2.0 because in 1.2 the interfaces inherited from
IInvokable
which gave them method RTTI by default.However, in 2.0 this has changed and neither the interfaces nor the objects backing them emit any enhanced RTTI simply because the interfaces don't inherit from
IInvokable
anymore nor have{$M+}
added to them, and in the implementing classes all enhanced RTTI is turned off via the$RTTI
clause. This is by design and to avoid causing lots of unnecessary binary bloat.Knowing that one of the major usages of using RTTI on collections is serialization Spring4D offers another approach:
Lists and many other collection types support the non-generic
ICollection
interface fromSpring.Collections
which internally creates a wrapper object around the generic collection and exposes functionality fromIEnumerable
and theAdd(const value: TValue)
andClear
methods.I have quickly looked into the DMVC code and I can say that they are handling interfaces in a poor way by simply casting them to object and passing that down. I don't know if they have some extension point for customizing serialization but this needs to be fixed.