Merge pull request #283 from joaoduarte19/serializer_enhancements

Serializer Enhancements
This commit is contained in:
Daniele Teti 2019-10-15 09:13:11 +02:00 committed by GitHub
commit 2830a7e27f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 5 deletions

View File

@ -54,6 +54,7 @@ type
function GetNameAs(const AOwner: TComponent; const AComponentName: string; const ADefaultValue: string): string;
function IsIgnoredAttribute(const AAttributes: TMVCIgnoredList; const AName: string): Boolean;
function IsIgnoredComponent(const AOwner: TComponent; const AComponentName: string): Boolean;
function GetObjectTypeOfGenericList(const ATypeInfo: PTypeInfo): TClass;
public
procedure RegisterTypeSerializer(const ATypeInfo: PTypeInfo; AInstance: IMVCTypeSerializer);
constructor Create;
@ -66,7 +67,8 @@ implementation
uses
MVCFramework.Cache,
MVCFramework.Logger;
MVCFramework.Logger,
System.SysUtils;
constructor TMVCAbstractSerializer.Create;
begin
@ -149,6 +151,32 @@ begin
end;
end;
function TMVCAbstractSerializer.GetObjectTypeOfGenericList(const ATypeInfo: PTypeInfo): TClass;
function ExtractGenericArguments(ATypeInfo: PTypeInfo): string;
var
I: Integer;
LTypeInfoName: string;
begin
LTypeInfoName := UTF8ToString(ATypeInfo.Name);
I := Pos('<', LTypeInfoName);
if I <= 0 then
Exit('');
Result := Copy(LTypeInfoName, Succ(I), Length(LTypeInfoName) - Succ(I));
end;
var
LType: string;
begin
LType := ExtractGenericArguments(ATypeInfo);
if LType.IsEmpty then
Exit(nil);
Result := GetRttiContext.FindType(LType).AsInstance.MetaclassType;
end;
function TMVCAbstractSerializer.GetRttiContext: TRttiContext;
begin
Result := FRttiContext;

View File

@ -731,6 +731,7 @@ var
ChildListOfAtt: MVCListOfAttribute;
LEnumAsAttr: MVCEnumSerializationTypeAttribute;
LEnumPrefix: string;
LClazz: TClass;
begin
if GetTypeSerializers.ContainsKey(AValue.TypeInfo) then
begin
@ -845,10 +846,14 @@ begin
else
begin
ChildList := TDuckTypedList.Wrap(ChildObject);
if TMVCSerializerHelper.AttributeExists<MVCListOfAttribute>(ACustomAttributes,
ChildListOfAtt) then
JsonArrayToList(AJsonObject.A[AName], ChildList, ChildListOfAtt.Value,
AType, AIgnored)
if TMVCSerializerHelper.AttributeExists<MVCListOfAttribute>(ACustomAttributes, ChildListOfAtt) then
LClazz := ChildListOfAtt.Value
else
LClazz := GetObjectTypeOfGenericList(AValue.TypeInfo);
if Assigned(LClazz) then
JsonArrayToList(AJsonObject.A[AName], ChildList, LClazz, AType, AIgnored)
else
raise EMVCDeserializationException.CreateFmt
('You can not deserialize a list %s without the MVCListOf attribute.', [AName]);

View File

@ -354,6 +354,19 @@ type
property Description: string read GetDescription write SetDescription;
end;
TGenericEntity<T: class> = class
private
FCode: Integer;
FItems: TObjectList<T>;
FDescription: string;
public
constructor Create;
destructor Destroy; override;
property Code: Integer read FCode write FCode;
property Description: string read FDescription write FDescription;
property Items: TObjectList<T> read FItems write FItems;
end;
implementation
@ -493,4 +506,18 @@ begin
FDescription := Value;
end;
{ TGenericEntity<T> }
constructor TGenericEntity<T>.Create;
begin
inherited Create;
FItems := TObjectList<T>.Create;
end;
destructor TGenericEntity<T>.Destroy;
begin
FItems.Free;
inherited Destroy;
end;
end.

View File

@ -107,6 +107,9 @@ type
procedure TestSerializeDeserializeGuid;
[Test]
procedure TestSerializeDeserializeEntityWithInterface;
[Test]
procedure TestSerializeDeserializeGenericEntity;
end;
TMVCEntityCustomSerializerJsonDataObjects = class(TInterfacedObject, IMVCTypeSerializer)
@ -1314,6 +1317,61 @@ begin
Assert.AreEqual('Child Entity', LEntity.ChildEntity.Description);
end;
procedure TMVCTestSerializerJsonDataObjects.TestSerializeDeserializeGenericEntity;
const
JSON =
'{' +
'"Code":1,' +
'"Description":"General Description",' +
'"Items":[' +
'{"Description":"Description 01"},' +
'{"Description":"Description 02"},' +
'{"Description":"Description 03"},' +
'{"Description":"Description 04"},' +
'{"Description":"Description 05"}' +
']'+
'}';
var
LGenericEntity: TGenericEntity<TNote>;
LJson: string;
begin
LGenericEntity := TGenericEntity<TNote>.Create;
try
LGenericEntity.Code := 1;
LGenericEntity.Description := 'General Description';
LGenericEntity.Items.Add(TNote.Create('Description 01'));
LGenericEntity.Items.Add(TNote.Create('Description 02'));
LGenericEntity.Items.Add(TNote.Create('Description 03'));
LGenericEntity.Items.Add(TNote.Create('Description 04'));
LGenericEntity.Items.Add(TNote.Create('Description 05'));
LJson := FSerializer.SerializeObject(LGenericEntity);
Assert.AreEqual(JSON, LJson);
finally
LGenericEntity.Free;
end;
LGenericEntity := TGenericEntity<TNote>.Create;
try
FSerializer.DeserializeObject(LJson, LGenericEntity);
Assert.AreEqual(Integer(1), LGenericEntity.Code);
Assert.AreEqual('General Description', LGenericEntity.Description);
Assert.AreEqual(Integer(5), LGenericEntity.Items.Count);
Assert.AreEqual('Description 01', LGenericEntity.Items[0].Description);
Assert.AreEqual('Description 02', LGenericEntity.Items[1].Description);
Assert.AreEqual('Description 03', LGenericEntity.Items[2].Description);
Assert.AreEqual('Description 04', LGenericEntity.Items[3].Description);
Assert.AreEqual('Description 05', LGenericEntity.Items[4].Description);
finally
LGenericEntity.Free;
end;
end;
procedure TMVCTestSerializerJsonDataObjects.TestSerializeDeserializeGuid;
const
JSON =