Completed refactoring about IMVCTypeSerializer

This commit is contained in:
Daniele Teti 2018-10-31 01:07:23 +01:00
parent 132e169542
commit 7ca4ccbe59
14 changed files with 426 additions and 284 deletions

View File

@ -57,7 +57,7 @@
## What's New
### 3.1.0 lithium (currently in beta)
### DelphiMVCFramework 3.1.0 lithium (currently in beta)
- New! Added `TMVCActiveRecord` framework (check sample `activerecord_showcase` and `activerecord_crud`)
- New! Added `TMVCActiveRecordController` (check sample `activerecord_crud`)
- Automatic permissions handling for `TMVCActiveRecordController` (check sample `activerecord_crud`)
@ -72,7 +72,7 @@
- New! Added method `TMVCJsonDataObjectsSerializer.ListToJsonArray`
- New! `TMVCResponse` for handle generic (non error) response
- New! `TMVCErrorResponse` for handle generic error response
- New! Added class `TMVCActiveRecordList` used in the no-automatic `TMVCActiveRecord` programming
- New! Added class `TMVCActiveRecordList` used in the manual `TMVCActiveRecord` programming
- New! Added `gzip` compression support in addition to `deflate` in `TCompressionMiddleware`
- FIX for [issue #143](https://github.com/danieleteti/delphimvcframework/issues/143)
- FIX for [issue #141](https://github.com/danieleteti/delphimvcframework/issues/141)
@ -82,6 +82,9 @@
- `TCompressionMiddleware` has been renamed in `TMVCCompressionMiddleware`
- New! `TMVCCompressionMiddleware` is added by IDE Expert by default
- Removed the old JSON serializer based on `System.JSON.pas', now the only available JSON serializer is based on [JsonDataObjects](https://github.com/ahausladen/JsonDataObjects) parser (Thank you Andreas Hausladen).
- Changed! Custom Types Serializer *must* be registered by media-type only, without charset definition (e.g. just `application/json` and not `application/json;charset=utf-8`)
- Changed! `IMVCTypeSerializer` is more powerful and simple to use!
- New! Support for Spring4d nullable types (check `samples\renders_spring4d_nullables`)
## How to correctly get the source

View File

@ -64,11 +64,11 @@ begin
FMVC.AddController(TMyController);
// To enable compression (deflate, gzip) just add this middleware as the last one
FMVC.AddMiddleware(TMVCCompressionMiddleware.Create);
FMVC.Serializers.Items[BuildContentType('application/json', 'utf-8')]
FMVC.Serializers.Items['application/json']
.RegisterTypeSerializer(typeinfo(Nullable<System.Integer>), TNullableIntegerSerializer.Create);
FMVC.Serializers.Items[BuildContentType('application/json', 'utf-8')]
FMVC.Serializers.Items['application/json']
.RegisterTypeSerializer(typeinfo(Nullable<System.Currency>), TNullableCurrencySerializer.Create);
FMVC.Serializers.Items[BuildContentType('application/json', 'utf-8')]
FMVC.Serializers.Items['application/json']
.RegisterTypeSerializer(typeinfo(Nullable<System.string>), TNullableStringSerializer.Create);
// FMVC.Serializers.Items[BuildContentType('application/json', 'utf-8')]
// .RegisterTypeSerializer(typeinfo(TPerson), TPersonSerializer.Create);

View File

@ -339,7 +339,11 @@ type
end;
TMVCStringDictionary = class
strict protected
strict
private
function GetItems(const Key: string): string;
procedure SetItems(const Key, Value: string);
protected
FDict: TDictionary<string, string>;
public
constructor Create; virtual;
@ -349,6 +353,8 @@ type
function TryGetValue(const Name: string; out Value: string): Boolean;
function Count: Integer;
function GetEnumerator: TDictionary<string, string>.TPairEnumerator;
function ContainsKey(const Key: string): Boolean;
property Items[const Key: string]: string read GetItems write SetItems; default;
end;
{ This type is thread safe }
@ -451,10 +457,10 @@ const
MVC_HTTP_METHODS_WITHOUT_CONTENT: TMVCHTTPMethods = [httpGET, httpDELETE, httpHEAD, httpOPTIONS];
MVC_HTTP_METHODS_WITH_CONTENT: TMVCHTTPMethods = [httpPOST, httpPUT, httpPATCH];
const
MVC_COMPRESSION_TYPE_AS_STRING: array [TMVCCompressionType] of string = ('none', 'deflate', 'gzip');
MVC_COMPRESSION_ZLIB_WINDOW_BITS: array [TMVCCompressionType] of Integer = (0, -15, 31); // WindowBits: http://zlib.net/manual.html#Advanced
MVC_COMPRESSION_ZLIB_WINDOW_BITS: array [TMVCCompressionType] of Integer = (0, -15, 31);
// WindowBits: http://zlib.net/manual.html#Advanced
var
Lock: TObject;
@ -753,6 +759,11 @@ begin
FDict.Clear;
end;
function TMVCStringDictionary.ContainsKey(const Key: string): Boolean;
begin
Result := FDict.ContainsKey(Key);
end;
function TMVCStringDictionary.Count: Integer;
begin
Result := FDict.Count;
@ -775,6 +786,17 @@ begin
Result := FDict.GetEnumerator;
end;
function TMVCStringDictionary.GetItems(const Key: string): string;
begin
Result := '';
FDict.TryGetValue(Key, Result);
end;
procedure TMVCStringDictionary.SetItems(const Key, Value: string);
begin
FDict.AddOrSetValue(Key, Value);
end;
function TMVCStringDictionary.TryGetValue(const Name: string; out Value: string): Boolean;
begin
Result := FDict.TryGetValue(name, Value);

View File

@ -188,7 +188,7 @@ begin
if not IsValid then
begin
AuthHeader := AContext.Request.Headers['Authorization'];
AuthHeader := TMVCSerializerHelpful.DecodeString(AuthHeader.Remove(0, 'Basic'.Length).Trim);
AuthHeader := TMVCSerializerHelper.DecodeString(AuthHeader.Remove(0, 'Basic'.Length).Trim);
AuthPieces := AuthHeader.Split([':']);
if AuthHeader.IsEmpty or (Length(AuthPieces) <> 2) then
begin

View File

@ -37,17 +37,15 @@ uses
System.DateUtils,
System.TypInfo,
{$IFDEF SYSTEMNETENCODING}
{$IFDEF SYSTEMNETENCODING}
System.NetEncoding,
{$ELSE}
{$ELSE}
Soap.EncdDecd,
{$ENDIF}
MVCFramework.Commons, Data.DB;
{$ENDIF}
MVCFramework.Commons,
Data.DB;
type
@ -167,18 +165,19 @@ type
property IsPK: boolean read FIsPK write SetIsPK;
end;
TMVCSerializerHelpful = record
TMVCSerializerHelper = record
private
{ private declarations }
public
class function GetKeyName(const AField: TRttiField; const AType: TRttiType): string; overload; static;
class function GetKeyName(const AProperty: TRttiProperty; const AType: TRttiType): string; overload; static;
class function HasAttribute<T: class>(const AMember: TRttiNamedObject): Boolean; overload; static;
class function HasAttribute<T: class>(const AMember: TRttiNamedObject; out AAttribute: T): Boolean; overload; static;
class function HasAttribute<T: class>(const AMember: TRttiNamedObject): boolean; overload; static;
class function HasAttribute<T: class>(const AMember: TRttiNamedObject; out AAttribute: T): boolean; overload; static;
class function AttributeExists<T: TCustomAttribute>(const AAttributes: TArray<TCustomAttribute>; out AAttribute: T): Boolean; overload; static;
class function AttributeExists<T: TCustomAttribute>(const AAttributes: TArray<TCustomAttribute>): Boolean; overload; static;
class function AttributeExists<T: TCustomAttribute>(const AAttributes: TArray<TCustomAttribute>; out AAttribute: T): boolean;
overload; static;
class function AttributeExists<T: TCustomAttribute>(const AAttributes: TArray<TCustomAttribute>): boolean; overload; static;
class procedure EncodeStream(AInput, AOutput: TStream); static;
class procedure DecodeStream(AInput, AOutput: TStream); static;
@ -195,7 +194,7 @@ type
class function CreateObject(const AObjectType: TRttiType): TObject; overload; static;
class function CreateObject(const AQualifiedClassName: string): TObject; overload; static;
class function IsAPropertyToSkip(const aPropName: string): Boolean; static;
class function IsAPropertyToSkip(const aPropName: string): boolean; static;
end;
function DateTimeToISOTimeStamp(const ADateTime: TDateTime): string;
@ -243,7 +242,8 @@ var
begin
lDateTime := ADateTime;
if lDateTime.Length < 19 then
raise Exception.CreateFmt('Invalid parameter "%s". Hint: DateTime parameters must be formatted in ISO8601 (e.g. 2010-10-12T10:12:23)', [ADateTime]);
raise Exception.CreateFmt('Invalid parameter "%s". Hint: DateTime parameters must be formatted in ISO8601 (e.g. 2010-10-12T10:12:23)',
[ADateTime]);
if lDateTime.Chars[10] = ' ' then
begin
@ -264,9 +264,9 @@ begin
Result := EncodeTime(StrToInt(Copy(ATime, 1, 2)), StrToInt(Copy(ATime, 4, 2)), StrToInt(Copy(ATime, 7, 2)), 0);
end;
{ TMVCSerializerHelpful }
{ TMVCSerializerHelper }
class procedure TMVCSerializerHelpful.DeSerializeBase64StringStream(
class procedure TMVCSerializerHelper.DeSerializeBase64StringStream(
AStream: TStream; const ABase64SerializedString: string);
var
SS: TStringStream;
@ -281,7 +281,7 @@ begin
end;
end;
class procedure TMVCSerializerHelpful.DeSerializeStringStream(AStream: TStream; const ASerializedString: string; const AEncoding: string);
class procedure TMVCSerializerHelper.DeSerializeStringStream(AStream: TStream; const ASerializedString: string; const AEncoding: string);
var
Encoding: TEncoding;
SS: TStringStream;
@ -297,7 +297,7 @@ begin
end;
end;
class function TMVCSerializerHelpful.GetKeyName(const AField: TRttiField; const AType: TRttiType): string;
class function TMVCSerializerHelper.GetKeyName(const AField: TRttiField; const AType: TRttiType): string;
var
Attrs: TArray<TCustomAttribute>;
Attr: TCustomAttribute;
@ -326,7 +326,7 @@ begin
end;
end;
class function TMVCSerializerHelpful.AttributeExists<T>(const AAttributes: TArray<TCustomAttribute>; out AAttribute: T): Boolean;
class function TMVCSerializerHelper.AttributeExists<T>(const AAttributes: TArray<TCustomAttribute>; out AAttribute: T): boolean;
var
Att: TCustomAttribute;
begin
@ -340,18 +340,18 @@ begin
Result := (AAttribute <> nil);
end;
class function TMVCSerializerHelpful.AttributeExists<T>(
const AAttributes: TArray<TCustomAttribute>): Boolean;
class function TMVCSerializerHelper.AttributeExists<T>(
const AAttributes: TArray<TCustomAttribute>): boolean;
var
Att: TCustomAttribute;
begin
Result := False;
Result := false;
for Att in AAttributes do
if Att is T then
Exit(True);
Exit(true);
end;
class function TMVCSerializerHelpful.CreateObject(const AObjectType: TRttiType): TObject;
class function TMVCSerializerHelper.CreateObject(const AObjectType: TRttiType): TObject;
var
MetaClass: TClass;
Method: TRttiMethod;
@ -373,7 +373,7 @@ begin
raise EMVCException.CreateFmt('Cannot find a propert constructor for %s', [AObjectType.ToString]);
end;
class function TMVCSerializerHelpful.CreateObject(const AQualifiedClassName: string): TObject;
class function TMVCSerializerHelper.CreateObject(const AQualifiedClassName: string): TObject;
var
Context: TRttiContext;
ObjectType: TRttiType;
@ -390,67 +390,59 @@ begin
end;
end;
class procedure TMVCSerializerHelpful.DecodeStream(AInput, AOutput: TStream);
class procedure TMVCSerializerHelper.DecodeStream(AInput, AOutput: TStream);
begin
{$IFDEF SYSTEMNETENCODING}
{$IFDEF SYSTEMNETENCODING}
TNetEncoding.Base64.Decode(AInput, AOutput);
{$ELSE}
{$ELSE}
Soap.EncdDecd.DecodeStream(AInput, AOutput);
{$ENDIF}
{$ENDIF}
end;
class function TMVCSerializerHelpful.DecodeString(const AInput: string): string;
class function TMVCSerializerHelper.DecodeString(const AInput: string): string;
begin
{$IFDEF SYSTEMNETENCODING}
{$IFDEF SYSTEMNETENCODING}
Result := TNetEncoding.Base64.Decode(AInput);
{$ELSE}
{$ELSE}
Result := Soap.EncdDecd.DecodeString(AInput);
{$ENDIF}
{$ENDIF}
end;
class procedure TMVCSerializerHelpful.EncodeStream(AInput, AOutput: TStream);
class procedure TMVCSerializerHelper.EncodeStream(AInput, AOutput: TStream);
begin
{$IFDEF SYSTEMNETENCODING}
{$IFDEF SYSTEMNETENCODING}
TNetEncoding.Base64.Encode(AInput, AOutput);
{$ELSE}
{$ELSE}
Soap.EncdDecd.EncodeStream(AInput, AOutput);
{$ENDIF}
{$ENDIF}
end;
class function TMVCSerializerHelpful.EncodeString(const AInput: string): string;
class function TMVCSerializerHelper.EncodeString(const AInput: string): string;
begin
{$IFDEF SYSTEMNETENCODING}
{$IFDEF SYSTEMNETENCODING}
Result := TNetEncoding.Base64.Encode(AInput);
{$ELSE}
{$ELSE}
Result := Soap.EncdDecd.EncodeString(AInput);
{$ENDIF}
{$ENDIF}
end;
class function TMVCSerializerHelpful.GetKeyName(const AProperty: TRttiProperty; const AType: TRttiType): string;
class function TMVCSerializerHelper.GetKeyName(const AProperty: TRttiProperty; const AType: TRttiType): string;
var
Attrs: TArray<TCustomAttribute>;
Attr: TCustomAttribute;
@ -479,49 +471,49 @@ begin
end;
end;
class function TMVCSerializerHelpful.GetTypeKindAsString(const ATypeKind: TTypeKind): string;
class function TMVCSerializerHelper.GetTypeKindAsString(const ATypeKind: TTypeKind): string;
begin
Result := GetEnumName(TypeInfo(TTypeKind), Ord(ATypeKind));
Result := Result.Remove(0, 2).ToLower;
end;
class function TMVCSerializerHelpful.HasAttribute<T>(const AMember: TRttiNamedObject): Boolean;
class function TMVCSerializerHelper.HasAttribute<T>(const AMember: TRttiNamedObject): boolean;
var
Attrs: TArray<TCustomAttribute>;
Attr: TCustomAttribute;
begin
Result := False;
Result := false;
Attrs := AMember.GetAttributes;
if Length(Attrs) = 0 then
Exit(False);
Exit(false);
for Attr in Attrs do
if Attr is T then
Exit(True);
Exit(true);
end;
class function TMVCSerializerHelpful.HasAttribute<T>(const AMember: TRttiNamedObject; out AAttribute: T): Boolean;
class function TMVCSerializerHelper.HasAttribute<T>(const AMember: TRttiNamedObject; out AAttribute: T): boolean;
var
Attrs: TArray<TCustomAttribute>;
Attr: TCustomAttribute;
begin
AAttribute := nil;
Result := False;
Result := false;
Attrs := AMember.GetAttributes;
for Attr in Attrs do
if Attr is T then
begin
AAttribute := T(Attr);
Exit(True);
Exit(true);
end;
end;
class function TMVCSerializerHelpful.IsAPropertyToSkip(
const aPropName: string): Boolean;
class function TMVCSerializerHelper.IsAPropertyToSkip(
const aPropName: string): boolean;
begin
Result := (aPropName = 'RefCount') or (aPropName = 'Disposed');
end;
class function TMVCSerializerHelpful.StringToTypeKind(const AValue: string): TTypeKind;
class function TMVCSerializerHelper.StringToTypeKind(const AValue: string): TTypeKind;
begin
Result := TTypeKind(GetEnumValue(TypeInfo(TTypeKind), 'tk' + AValue));
end;

View File

@ -39,9 +39,7 @@ uses
type
TStreamSerializerJsonDataObject = class(TInterfacedObject, IMVCTypeSerializer)
private
{ private declarations }
TMVCStreamSerializerJsonDataObject = class(TInterfacedObject, IMVCTypeSerializer)
protected
// procedure Serialize(const AElementValue: TValue; var ASerializerObject: TObject;
// const AAttributes: TArray<TCustomAttribute>);
@ -65,11 +63,9 @@ type
);
procedure DeserializeRoot(
const ASerializerObject: TObject; const AObject: TObject;
const AAttributes: TArray<TCustomAttribute>);
procedure Deserialize(const ASerializedObject: TObject; var AElementValue: TValue;
const ASerializerObject: TObject; const AObject: TObject;
const AAttributes: TArray<TCustomAttribute>);
public
{ public declarations }
end;
@ -99,9 +95,6 @@ type
const AObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
procedure Deserialize(const ASerializedObject: TObject; var AElementValue: TValue;
const AAttributes: System.TArray<System.TCustomAttribute>);
end;
implementation
@ -113,99 +106,53 @@ uses
System.Generics.Collections,
JsonDataObjects;
{ TStreamSerializerJsonDataObject }
procedure TStreamSerializerJsonDataObject.Deserialize(const ASerializedObject: TObject; var AElementValue: TValue;
const AAttributes: TArray<TCustomAttribute>);
var
JsonValue: TJsonValue;
Stream: TStream;
SS: TStringStream;
begin
JsonValue := ASerializedObject as TJsonValue;
if Assigned(JsonValue) then
begin
Stream := AElementValue.AsObject as TStream;
if Assigned(Stream) then
begin
if TMVCSerializerHelpful.AttributeExists<MVCSerializeAsStringAttribute>(AAttributes) then
begin
SS := TStringStream.Create(JsonValue.Value);
try
SS.Position := 0;
Stream.CopyFrom(SS, SS.Size);
finally
SS.Free;
end;
end
else
begin
SS := TStringStream.Create(JsonValue.Value);
try
SS.Position := 0;
TMVCSerializerHelpful.DecodeStream(SS, Stream);
finally
SS.Free;
end;
end;
end;
end;
end;
// procedure TStreamSerializerJsonDataObject.Serialize(const AElementValue: TValue; var ASerializerObject: TObject;
// const AAttributes: TArray<TCustomAttribute>);
// var
// Stream: TStream;
// SS: TStringStream;
// DataString: string;
// begin
// Stream := AElementValue.AsObject as TStream;
// if Assigned(Stream) then
// begin
// if TMVCSerializerHelpful.AttributeExists<MVCSerializeAsStringAttribute>(AAttributes) then
// begin
// Stream.Position := 0;
// SS := TStringStream.Create;
// try
// SS.CopyFrom(Stream, Stream.Size);
// DataString := SS.DataString;
// ASerializerObject := TJsonValue.Create(SS.DataString);
// finally
// SS.Free;
// end;
// end
// else
// begin
// SS := TStringStream.Create;
// try
// Stream.Position := 0;
// TMVCSerializerHelpful.EncodeStream(Stream, SS);
// ASerializerObject := TJsonValue.Create(SS.DataString);
// finally
// SS.Free;
// end;
// end;
// end;
// end;
procedure TStreamSerializerJsonDataObject.DeserializeAttribute(
procedure TMVCStreamSerializerJsonDataObject.DeserializeAttribute(
var AElementValue: TValue;
const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
var
lStream: TStream;
SS: TStringStream;
lJSON: TJDOJsonObject;
begin
lJSON := ASerializerObject as TJDOJsonObject;
if Assigned(lJSON) then
begin
lStream := AElementValue.AsObject as TStream;
lStream.Size := 0;
if Assigned(lStream) then
begin
SS := TStringStream.Create(lJSON.S[APropertyName]);
try
SS.Position := 0;
if TMVCSerializerHelper.AttributeExists<MVCSerializeAsStringAttribute>(AAttributes) then
begin
lStream.CopyFrom(SS, 0);
end
else
begin
TMVCSerializerHelper.DecodeStream(SS, lStream);
end;
finally
SS.Free;
end;
end;
end;
end;
procedure TStreamSerializerJsonDataObject.DeserializeRoot(
procedure TMVCStreamSerializerJsonDataObject.DeserializeRoot(
const ASerializerObject: TObject; const AObject: TObject;
const AAttributes: TArray<TCustomAttribute>);
var
lValue: TValue;
begin
raise Exception.Create('Not implemented');
lValue := AObject;
DeserializeAttribute(lValue, 'data', ASerializerObject, AAttributes);
end;
procedure TStreamSerializerJsonDataObject.SerializeAttribute(
procedure TMVCStreamSerializerJsonDataObject.SerializeAttribute(
const AElementValue: TValue; const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>);
@ -216,7 +163,7 @@ begin
Stream := AElementValue.AsObject as TStream;
if Assigned(Stream) then
begin
if TMVCSerializerHelpful.AttributeExists<MVCSerializeAsStringAttribute>(AAttributes) then
if TMVCSerializerHelper.AttributeExists<MVCSerializeAsStringAttribute>(AAttributes) then
begin
SS := TStringStream.Create;
try
@ -232,7 +179,7 @@ begin
SS := TStringStream.Create;
try
Stream.Position := 0;
TMVCSerializerHelpful.EncodeStream(Stream, SS);
TMVCSerializerHelper.EncodeStream(Stream, SS);
TJsonObject(ASerializerObject).S[APropertyName] := SS.DataString;
finally
SS.Free;
@ -245,7 +192,7 @@ begin
end;
end;
procedure TStreamSerializerJsonDataObject.SerializeRoot(const AObject: TObject;
procedure TMVCStreamSerializerJsonDataObject.SerializeRoot(const AObject: TObject;
out ASerializerObject: TObject; const AAttributes: TArray<TCustomAttribute>);
var
lSerializerObject: TJsonObject;
@ -261,29 +208,41 @@ end;
{ TMVCStringDictionarySerializer }
procedure TMVCStringDictionarySerializer.Deserialize(const ASerializedObject: TObject; var AElementValue: TValue;
const AAttributes: System.TArray<System.TCustomAttribute>);
begin
raise EMVCDeserializationException.Create('Not Implemented');
end;
procedure TMVCStringDictionarySerializer.DeserializeAttribute(
var AElementValue: TValue;
const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
var
lStringDict: TMVCStringDictionary;
lJSON: TJDOJsonObject;
i: Integer;
begin
lStringDict := AElementValue.AsObject as TMVCStringDictionary;
lJSON := ASerializerObject as TJDOJsonObject;
for i := 0 to lJSON.O[APropertyName].Count - 1 do
begin
lStringDict.AddProperty(lJSON.Names[i], lJSON.S[lJSON.Names[i]])
end;
end;
procedure TMVCStringDictionarySerializer.DeserializeRoot(
const ASerializerObject: TObject;
const AObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
const ASerializerObject: TObject;
const AObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
var
lStringDict: TMVCStringDictionary;
lJSON: TJDOJsonObject;
i: Integer;
begin
raise Exception.Create('Not implemented');
lStringDict := AObject as TMVCStringDictionary;
lJSON := ASerializerObject as TJDOJsonObject;
for i := 0 to lJSON.Count - 1 do
begin
lStringDict.AddProperty(lJSON.Names[i], lJSON.S[lJSON.Names[i]])
end;
end;
procedure TMVCStringDictionarySerializer.SerializeAttribute(

View File

@ -43,29 +43,12 @@ uses
MVCFramework.Serializer.Abstract,
MVCFramework.Serializer.Commons,
MVCFramework.DuckTyping,
MVCFramework.TypesAliases,
JsonDataObjects {JsonDataObjects must be after MVCFramework.TypesAliases};
MVCFramework.TypesAliases, {do not remove this!! Require a custom type serializer!}
JsonDataObjects {JsonDataObjects must be after MVCFramework.TypesAliases, if present};
type
TJsonValue = class
private
FValue: string;
protected
{ protected declarations }
public
constructor Create; overload;
constructor Create(const AValue: string); overload;
property Value: string read FValue write FValue;
end;
TMVCJsonDataObjectsSerializer = class(TMVCAbstractSerializer, IMVCSerializer)
public
// procedure SerializeDynamicArray(
// const AValue: TValue;
// const AArray: TJsonArray;
// const AType: TMVCSerializationType;
// const AIgnoredAttributes: TMVCIgnoredList
// );
procedure ObjectToJsonObject(const AObject: TObject; const AJsonObject: TJsonObject;
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
procedure ListToJsonArray(const AList: IMVCList; const AJsonArray: TJsonArray;
@ -133,10 +116,10 @@ uses
procedure TMVCJsonDataObjectsSerializer.AfterConstruction;
begin
inherited AfterConstruction;
GetTypeSerializers.Add(System.TypeInfo(TStream), TStreamSerializerJsonDataObject.Create);
GetTypeSerializers.Add(System.TypeInfo(TStringStream), TStreamSerializerJsonDataObject.Create);
GetTypeSerializers.Add(System.TypeInfo(TMemoryStream), TStreamSerializerJsonDataObject.Create);
GetTypeSerializers.Add(System.TypeInfo(TMVCStringDictionary), TMVCStringDictionarySerializer.Create);
GetTypeSerializers.Add(TypeInfo(TStream), TMVCStreamSerializerJsonDataObject.Create);
GetTypeSerializers.Add(TypeInfo(TStringStream), TMVCStreamSerializerJsonDataObject.Create);
GetTypeSerializers.Add(TypeInfo(TMemoryStream), TMVCStreamSerializerJsonDataObject.Create);
GetTypeSerializers.Add(TypeInfo(TMVCStringDictionary), TMVCStringDictionarySerializer.Create);
end;
procedure TMVCJsonDataObjectsSerializer.AttributeToJsonDataValue(
@ -152,7 +135,6 @@ var
ChildValue: TValue;
ChildObject, Obj: TObject;
ChildList: IMVCList;
// ChildJsonValue: TObject;
ValueTypeAtt: MVCValueAsTypeAttribute;
CastValue, CastedValue: TValue;
begin
@ -164,26 +146,7 @@ begin
if GetTypeSerializers.ContainsKey(AValue.TypeInfo) then
begin
// ChildJsonValue := nil;
// GetTypeSerializers.Items[AValue.TypeInfo].Serialize(AValue, ChildJsonValue, ACustomAttributes);
GetTypeSerializers.Items[AValue.TypeInfo].SerializeAttribute(AValue, AName, AJsonObject, ACustomAttributes);
// if Assigned(ChildJsonValue) then
// begin
// if ChildJsonValue is TJsonObject then
// AJsonObject.O[AName] := TJsonObject(ChildJsonValue)
// else if ChildJsonValue is TJsonArray then
// AJsonObject.A[AName] := TJsonArray(ChildJsonValue)
// else if ChildJsonValue is TJsonBaseObject then
// AJsonObject[AName] := ChildJsonValue
// else if ChildJsonValue is TJsonValue then
// begin
// AJsonObject[AName] := TJsonValue(ChildJsonValue).Value;
// ChildJsonValue.Free;
// end
// else
// raise EMVCSerializationException.CreateFmt
// ('Cannot serialize %s the serializer does not have a valid TJsonBaseObject type.', [AName]);
// end;
Exit;
end;
@ -238,8 +201,6 @@ begin
end
else
AJsonObject.S[AName] := GetEnumName(AValue.TypeInfo, AValue.AsOrdinal);
// AJSONObject.AddPair(AName, GetEnumName(AValue.TypeInfo, AValue.AsOrdinal));
// AJsonObject.L[AName] := AValue.AsOrdinal;
end;
tkClass:
@ -271,7 +232,7 @@ begin
end
else
begin
if TMVCSerializerHelpful.AttributeExists<MVCSerializeAsStringAttribute>(ACustomAttributes) then
if TMVCSerializerHelper.AttributeExists<MVCSerializeAsStringAttribute>(ACustomAttributes) then
AJsonObject.S[AName] := EmptyStr
else
AJsonObject[AName] := Null;
@ -286,7 +247,7 @@ begin
end
else if (AValue.TypeInfo = System.TypeInfo(TValue)) then
begin
if TMVCSerializerHelpful.AttributeExists<MVCValueAsTypeAttribute>(ACustomAttributes, ValueTypeAtt) then
if TMVCSerializerHelper.AttributeExists<MVCValueAsTypeAttribute>(ACustomAttributes, ValueTypeAtt) then
begin
CastValue := AValue.AsType<TValue>;
if CastValue.TryCast(ValueTypeAtt.ValueTypeInfo, CastedValue) then
@ -299,7 +260,7 @@ begin
begin
ChildValue := AValue.AsType<TValue>;
ChildJsonObject := AJsonObject.O[AName];
ChildJsonObject.S['type'] := TMVCSerializerHelpful.GetTypeKindAsString(ChildValue.TypeInfo.Kind);
ChildJsonObject.S['type'] := TMVCSerializerHelper.GetTypeKindAsString(ChildValue.TypeInfo.Kind);
AttributeToJsonDataValue(ChildJsonObject, 'value', ChildValue, stDefault, [], []);
end;
end
@ -312,9 +273,7 @@ begin
tkArray, tkDynArray:
begin
raise EMVCSerializationException.CreateFmt('Cannot serialize %s of TypeKind tkSet.', [AName]);
// ChildJsonArray := AJsonObject.A[AName];
// SerializeDynamicArray(AValue, ChildJsonArray, AType, AIgnored);
raise EMVCSerializationException.CreateFmt('Cannot serialize %s of TypeKind tkArray or tkDynArray.', [AName]);
end;
tkUnknown:
@ -414,7 +373,7 @@ begin
MS.Position := 0;
SS := TStringStream.Create;
try
TMVCSerializerHelpful.EncodeStream(MS, SS);
TMVCSerializerHelper.EncodeStream(MS, SS);
AJsonObject.S[FieldName] := SS.DataString;
finally
SS.Free;
@ -464,7 +423,7 @@ var
ObjList: IMVCList;
begin
if (ASerializedList = EmptyStr) then
Exit;
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
if not Assigned(AList) then
Exit;
@ -487,16 +446,26 @@ procedure TMVCJsonDataObjectsSerializer.DeserializeDataSet(
const AIgnoredFields: TMVCIgnoredList;
const ANameCase: TMVCNameCase);
var
JsonArray: TJsonArray;
lJsonArray: TJsonArray;
begin
if (ASerializedDataSet = EmptyStr) or (not Assigned(ADataSet)) then
if (ASerializedDataSet = EmptyStr) then
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
if not Assigned(ADataSet) then
Exit;
JsonArray := TJsonArray.Parse(ASerializedDataSet) as TJsonArray;
try
JsonArrayToDataSet(JsonArray, ADataSet, AIgnoredFields, ANameCase);
lJsonArray := TJsonArray.Parse(ASerializedDataSet) as TJsonArray;
except
on E: EJsonParserException do
begin
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
end;
end;
try
JsonArrayToDataSet(lJsonArray, ADataSet, AIgnoredFields, ANameCase);
finally
JsonArray.Free;
lJsonArray.Free;
end;
end;
@ -506,18 +475,25 @@ procedure TMVCJsonDataObjectsSerializer.DeserializeDataSetRecord(
const AIgnoredFields: TMVCIgnoredList;
const ANameCase: TMVCNameCase);
var
JsonObject: TJsonObject;
lJsonObject: TJsonObject;
begin
if (ASerializedDataSetRecord = EmptyStr) or (not Assigned(ADataSet)) then
Exit;
JsonObject := TJsonObject.Parse(ASerializedDataSetRecord) as TJsonObject;
try
lJsonObject := TJsonObject.Parse(ASerializedDataSetRecord) as TJsonObject;
except
on E: EJsonParserException do
begin
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
end;
end;
try
ADataSet.Edit;
JsonObjectToDataSet(JsonObject, ADataSet, AIgnoredFields, ANameCase);
JsonObjectToDataSet(lJsonObject, ADataSet, AIgnoredFields, ANameCase);
ADataSet.Post;
finally
JsonObject.Free;
lJsonObject.Free;
end;
end;
@ -545,7 +521,7 @@ var
begin
for I := 0 to Pred(AJsonArray.Count) do
begin
Obj := TMVCSerializerHelpful.CreateObject(AClazz.QualifiedClassName);
Obj := TMVCSerializerHelper.CreateObject(AClazz.QualifiedClassName);
JsonObjectToObject(AJsonArray.Items[I].ObjectValue, Obj, GetSerializationType(Obj, AType), AIgnoredAttributes);
AList.Add(Obj);
end;
@ -643,7 +619,7 @@ begin
if Assigned(ChildObject) then
begin
ChildList := TDuckTypedList.Wrap(ChildObject);
if TMVCSerializerHelpful.AttributeExists<MVCListOfAttribute>(ACustomAttributes, ChildListOfAtt) then
if TMVCSerializerHelper.AttributeExists<MVCListOfAttribute>(ACustomAttributes, ChildListOfAtt) then
JsonArrayToList(AJsonObject.A[AName], ChildList, ChildListOfAtt.Value, AType, AIgnored)
else
raise EMVCDeserializationException.CreateFmt
@ -730,7 +706,7 @@ begin
SS.Position := 0;
SM := TMemoryStream.Create;
try
TMVCSerializerHelpful.DecodeStream(SS, SM);
TMVCSerializerHelper.DecodeStream(SS, SM);
TBlobField(Field).LoadFromStream(SM);
finally
SM.Free;
@ -794,11 +770,11 @@ begin
{$ENDIF}
if (Prop.IsWritable or Prop.GetValue(AObject).IsObject) and
(not TMVCSerializerHelpful.HasAttribute<MVCDoNotSerializeAttribute>(Prop)) and
(not TMVCSerializerHelper.HasAttribute<MVCDoNotSerializeAttribute>(Prop)) and
(not IsIgnoredAttribute(AIgnoredAttributes, Prop.Name)) then
begin
AttributeValue := Prop.GetValue(AObject);
lKeyName := TMVCSerializerHelpful.GetKeyName(Prop, ObjType);
lKeyName := TMVCSerializerHelper.GetKeyName(Prop, ObjType);
JsonDataValueToAttribute(AJsonObject, lKeyName, AttributeValue,
AType, AIgnoredAttributes, Prop.GetAttributes);
if (not AttributeValue.IsEmpty) and Prop.IsWritable then
@ -816,11 +792,11 @@ begin
begin
try
for Fld in ObjType.GetFields do
if (not TMVCSerializerHelpful.HasAttribute<MVCDoNotSerializeAttribute>(Fld)) and
if (not TMVCSerializerHelper.HasAttribute<MVCDoNotSerializeAttribute>(Fld)) and
(not IsIgnoredAttribute(AIgnoredAttributes, Fld.Name)) then
begin
AttributeValue := Fld.GetValue(AObject);
lKeyName := TMVCSerializerHelpful.GetKeyName(Fld, ObjType);
lKeyName := TMVCSerializerHelper.GetKeyName(Fld, ObjType);
JsonDataValueToAttribute(AJsonObject, lKeyName, AttributeValue, AType,
AIgnoredAttributes, Fld.GetAttributes);
if not AttributeValue.IsEmpty then
@ -869,18 +845,18 @@ begin
Continue;
{$ENDIF}
if (not TMVCSerializerHelpful.HasAttribute<MVCDoNotSerializeAttribute>(Prop)) and
if (not TMVCSerializerHelper.HasAttribute<MVCDoNotSerializeAttribute>(Prop)) and
(not IsIgnoredAttribute(AIgnoredAttributes, Prop.Name)) then
AttributeToJsonDataValue(AJsonObject, TMVCSerializerHelpful.GetKeyName(Prop, ObjType),
AttributeToJsonDataValue(AJsonObject, TMVCSerializerHelper.GetKeyName(Prop, ObjType),
Prop.GetValue(AObject), AType, AIgnoredAttributes, Prop.GetAttributes);
end;
end;
stFields:
begin
for Fld in ObjType.GetFields do
if (not TMVCSerializerHelpful.HasAttribute<MVCDoNotSerializeAttribute>(Fld)) and
if (not TMVCSerializerHelper.HasAttribute<MVCDoNotSerializeAttribute>(Fld)) and
(not IsIgnoredAttribute(AIgnoredAttributes, Fld.Name)) then
AttributeToJsonDataValue(AJsonObject, TMVCSerializerHelpful.GetKeyName(Fld, ObjType), Fld.GetValue(AObject),
AttributeToJsonDataValue(AJsonObject, TMVCSerializerHelper.GetKeyName(Fld, ObjType), Fld.GetValue(AObject),
AType, AIgnoredAttributes, Fld.GetAttributes);
end;
end;
@ -1030,41 +1006,33 @@ procedure TMVCJsonDataObjectsSerializer.DeserializeObject(const ASerializedObjec
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
var
JsonObject: TJsonObject;
ObjType: TRttiType;
begin
if (ASerializedObject = EmptyStr) then
raise Exception.Create('Invalid body');
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
if not Assigned(AObject) then
Exit;
JsonObject := TJsonObject.Parse(ASerializedObject) as TJsonObject;
try
ObjType := GetRttiContext.GetType(AObject.ClassType);
if GetTypeSerializers.ContainsKey(ObjType.Handle) then
JsonObject := TJsonObject.Parse(ASerializedObject) as TJsonObject;
except
on E: EJsonParserException do
begin
// ObjValue := TValue.From<TObject>(AObject);
GetTypeSerializers.Items[ObjType.Handle].DeserializeRoot(JsonObject, AObject, []);
Exit;
raise EMVCException.Create(http_status.BadRequest, E.Message);
end;
end;
try
if GetTypeSerializers.ContainsKey(AObject.ClassInfo) then
begin
GetTypeSerializers.Items[AObject.ClassInfo].DeserializeRoot(JsonObject, AObject, []);
end
else
begin
JsonObjectToObject(JsonObject, AObject, GetSerializationType(AObject, AType), AIgnoredAttributes);
end;
JsonObjectToObject(JsonObject, AObject, GetSerializationType(AObject, AType), AIgnoredAttributes);
finally
JsonObject.Free;
end;
end;
{ TJsonValue }
constructor TJsonValue.Create;
begin
inherited Create;
FValue := EmptyStr;
end;
constructor TJsonValue.Create(const AValue: string);
begin
Create;
FValue := AValue;
end;
end.

View File

@ -54,7 +54,7 @@ uses
MVCFramework.ApplicationSession,
MVCFramework.Serializer.Intf,
MVCFramework.Serializer.Commons,
//MVCFramework.Serializer.JSON,
// MVCFramework.Serializer.JSON,
{$IFDEF WEBAPACHEHTTP}
Web.ApacheHTTP, // Apache Support since XE6 http://docwiki.embarcadero.com/Libraries/XE6/de/Web.ApacheHTTP
@ -848,9 +848,9 @@ var
lSerializer: IMVCSerializer;
begin
Result := nil;
if FSerializers.TryGetValue(ContentType, lSerializer) then
if FSerializers.TryGetValue(ContentMediaType, lSerializer) then
begin
Obj := TMVCSerializerHelpful.CreateObject(TClass(T).QualifiedClassName);
Obj := TMVCSerializerHelper.CreateObject(TClass(T).QualifiedClassName);
try
lSerializer.DeserializeObject(Body, Obj);
Result := Obj as T;
@ -872,7 +872,7 @@ var
lSerializer: IMVCSerializer;
begin
Result := nil;
if FSerializers.TryGetValue(ContentType, lSerializer) then
if FSerializers.TryGetValue(ContentMediaType, lSerializer) then
begin
List := TObjectList<T>.Create(True);
try
@ -892,7 +892,7 @@ var
lSerializer: IMVCSerializer;
begin
if Assigned(AObject) then
if FSerializers.TryGetValue(ContentType, lSerializer) then
if FSerializers.TryGetValue(ContentMediaType, lSerializer) then
lSerializer.DeserializeObject(Body, AObject)
else
raise EMVCException.CreateFmt('Body ContentType "%s" not supported', [ContentType]);
@ -903,7 +903,7 @@ var
lSerializer: IMVCSerializer;
begin
if Assigned(AObjectList) then
if FSerializers.TryGetValue(ContentType, lSerializer) then
if FSerializers.TryGetValue(ContentMediaType, lSerializer) then
lSerializer.DeserializeCollection(Body, AObjectList, T)
else
raise EMVCException.CreateFmt('Body ContentType "%s" not supported', [ContentType]);

View File

@ -210,8 +210,10 @@ type
TEntityCustomWithNullables = class(TEntityCustom)
private
FNullableInteger: TMVCNullable<Integer>;
FNullableString: TMVCNullable<string>;
public
property NullableInteger: TMVCNullable<Integer> read FNullableInteger write FNullableInteger;
property NullableString: TMVCNullable<string> read FNullableString write FNullableString;
end;
TColorEnum = (RED, GREEN, BLUE);
@ -225,6 +227,7 @@ type
public
property Id: Int64 read FId write FId;
property Code: Integer read FCode write FCode;
[MVCNameAs('Name')]
property name: string read FName write FName;
property Color: TColorEnum read FColor write FColor;
end;
@ -250,6 +253,7 @@ type
public
property Id: Int64 read FId write FId;
property Code: Integer read FCode write FCode;
[MVCNameAs('Name')]
property name: string read FName write FName;
end;

View File

@ -30,7 +30,8 @@ uses
MVCFramework.Patches in '..\..\..\sources\MVCFramework.Patches.pas',
JSONRPCTestsU in 'JSONRPCTestsU.pas',
MVCFramework.JSONRPC in '..\..\..\sources\MVCFramework.JSONRPC.pas',
RandomUtilsU in '..\..\..\samples\commons\RandomUtilsU.pas';
RandomUtilsU in '..\..\..\samples\commons\RandomUtilsU.pas',
MVCFramework.Serializer.JsonDataObjects in '..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas';
{$R *.RES}

View File

@ -158,6 +158,7 @@
<DCCReference Include="JSONRPCTestsU.pas"/>
<DCCReference Include="..\..\..\sources\MVCFramework.JSONRPC.pas"/>
<DCCReference Include="..\..\..\samples\commons\RandomUtilsU.pas"/>
<DCCReference Include="..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.pas"/>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>

View File

@ -177,6 +177,10 @@ type
procedure TestTypedDateTimeTypes;
[Test]
procedure TestTypedBooleans;
[Test]
procedure TestStringDictionary;
[Test]
procedure TestWrongJSONBody;
end;
[TestFixture]
@ -1102,6 +1106,31 @@ begin
DoLogout;
end;
procedure TServerTest.TestStringDictionary;
var
LRes: IRESTResponse;
lSer: TMVCJsonDataObjectsSerializer;
lDict: TMVCStringDictionary;
begin
LRes := RESTClient.doPOST('/stringdictionary', [], '{"prop1":"value1","prop2":"value2"}');
Assert.areEqual(200, LRes.ResponseCode);
lSer := TMVCJsonDataObjectsSerializer.Create;
try
lDict := TMVCStringDictionary.Create;
try
lSer.DeserializeObject(LRes.BodyAsString, lDict);
Assert.areEqual(3, lDict.Count);
Assert.areEqual('value1', lDict['prop1']);
Assert.areEqual('value2', lDict['prop2']);
Assert.areEqual('changed', lDict['fromserver']);
finally
lDict.Free;
end;
finally
lSer.Free;
end;
end;
procedure TServerTest.TestTypedAll;
var
res: IRESTResponse;
@ -1189,6 +1218,14 @@ begin
Assert.areEqual('daniele modified from server', res.BodyAsString);
end;
procedure TServerTest.TestWrongJSONBody;
var
LRes: IRESTResponse;
begin
LRes := RESTClient.doPOST('/stringdictionary', [], '{"prop1","value1"}');
Assert.areEqual(HTTP_STATUS.BadRequest, LRes.ResponseCode);
end;
procedure TServerTest.TestTypedDateTimeTypes;
var
res: IRESTResponse;

View File

@ -180,6 +180,9 @@ type
[MVCPath('/renderstreamandfreewithownertrue')]
procedure TestRenderStreamAndFreeWithOwnerTrue;
[MVCPath('/stringdictionary')]
procedure TestStringDictionary;
end;
[MVCPath('/private')]
@ -496,6 +499,19 @@ begin
Render(LStream, True);
end;
procedure TTestServerController.TestStringDictionary;
var
lDict: TMVCStringDictionary;
begin
lDict := Context.Request.BodyAs<TMVCStringDictionary>;
try
lDict['fromserver'] := 'changed';
Render(lDict, false);
finally
lDict.Free;
end;
end;
procedure TTestServerController.TestTypedActionAllTypes(ParString: string; ParInteger: Integer; ParInt64: Int64; ParSingle: Single;
ParDouble: Double; ParExtended: Extended);
var

View File

@ -94,6 +94,9 @@ type
{ full cycle }
[Test]
procedure TestSerializeDeSerializeEntityWithEnums;
[Test]
procedure TestStringDictionary;
end;
TMVCEntityCustomSerializerJsonDataObjects = class(TInterfacedObject, IMVCTypeSerializer)
@ -109,10 +112,37 @@ type
procedure SerializeAttribute(const AElementValue: TValue;
const APropertyName: string; const ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
procedure DeserializeRoot(const ASerializerObject: TObject;
const AObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
procedure DeserializeAttribute(var AElementValue: TValue;
const APropertyName: string; const ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
end;
TMVCNullableIntegerSerializerJsonDataObjects = class(TInterfacedObject, IMVCTypeSerializer)
public
procedure DeserializeAttribute(var AElementValue: TValue;
const APropertyName: string; const ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
procedure DeserializeRoot(const ASerializerObject: TObject;
const AObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
procedure SerializeAttribute(const AElementValue: TValue;
const APropertyName: string; const ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
procedure SerializeRoot(const AObject: TObject;
out ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
end;
implementation
uses
MVCFramework.Serializer.JsonDataObjects.CustomTypes,
MVCFramework.Commons;
const
LINE_BREAK = #$A;
TAB_SPACE = #9;
@ -123,7 +153,11 @@ procedure TMVCTestSerializerJsonDataObjects.Setup;
begin
inherited;
FSerializer := TMVCJsonDataObjectsSerializer.Create;
FSerializer.RegisterTypeSerializer(System.TypeInfo(TStream), TStreamSerializerJsonDataObject.Create);
FSerializer.RegisterTypeSerializer(System.TypeInfo(TStringStream), TStreamSerializerJsonDataObject.Create);
FSerializer.RegisterTypeSerializer(System.TypeInfo(TMemoryStream), TStreamSerializerJsonDataObject.Create);
FSerializer.RegisterTypeSerializer(System.TypeInfo(TEntityCustom), TMVCEntityCustomSerializerJsonDataObjects.Create);
FSerializer.RegisterTypeSerializer(System.TypeInfo(TMVCNullable<Integer>), TMVCNullableIntegerSerializerJsonDataObjects.Create);
end;
procedure TMVCTestSerializerJsonDataObjects.TearDown;
@ -446,9 +480,9 @@ const
JSON =
'{' +
'"Entity":{' +
'"AId":1,' +
'"ACode":2,' +
'"AName":"Ezequiel Juliano Müller"' +
'"Id":1,' +
'"Code":2,' +
'"Name":"Ezequiel Juliano Müller"' +
'},' +
'"Notes":"RXplcXVpZWwgSnVsaWFubyBN/GxsZXI=",' +
'"NotesAsString":"Ezequiel Juliano Müller"' +
@ -473,9 +507,9 @@ procedure TMVCTestSerializerJsonDataObjects.TestDeserializeEntityCustomSerialize
const
JSON =
'{' +
'"AId":1,' +
'"ACode":2,' +
'"AName":"Ezequiel Juliano Müller"' +
'"Id":1,' +
'"Code":2,' +
'"Name":"Ezequiel Juliano Müller"' +
'}';
var
O: TEntityCustom;
@ -1131,6 +1165,35 @@ begin
Assert.areEqual('null', FSerializer.SerializeObject(nil));
end;
procedure TMVCTestSerializerJsonDataObjects.TestStringDictionary;
var
lDict: TMVCStringDictionary;
lSerString: string;
lDict2: TMVCStringDictionary;
begin
lDict := TMVCStringDictionary.Create;
try
lDict['prop1'] := 'value1';
lDict['prop2'] := 'value2';
lDict['prop3'] := 'value3';
lSerString := FSerializer.SerializeObject(lDict);
lDict2 := TMVCStringDictionary.Create;
try
FSerializer.DeserializeObject(lSerString, lDict2);
Assert.isTrue(lDict2.ContainsKey('prop1'));
Assert.isTrue(lDict2.ContainsKey('prop2'));
Assert.isTrue(lDict2.ContainsKey('prop3'));
Assert.areEqual(lDict['prop1'], lDict2['prop1']);
Assert.areEqual(lDict['prop2'], lDict2['prop2']);
Assert.areEqual(lDict['prop3'], lDict2['prop3']);
finally
lDict2.Free;
end;
finally
lDict.Free;
end;
end;
{ TMVCEntityCustomSerializerJsonDataObjects }
procedure TMVCEntityCustomSerializerJsonDataObjects.Deserialize(
@ -1153,6 +1216,50 @@ begin
end;
end;
procedure TMVCEntityCustomSerializerJsonDataObjects.DeserializeAttribute(
var AElementValue: TValue; const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
begin
DeserializeRoot(ASerializerObject, AElementValue.AsObject, AAttributes);
end;
procedure TMVCEntityCustomSerializerJsonDataObjects.DeserializeRoot(
const ASerializerObject, AObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
var
lEntity: TEntityCustom;
lJSON: TJDOJsonObject;
lAttr: TCustomAttribute;
lAsLowerCase: Boolean;
begin
lEntity := TEntityCustom(AObject);
lJSON := ASerializerObject as TJDOJsonObject;
lAsLowerCase := False;
for lAttr in AAttributes do
begin
if lAttr is MVCNameCaseAttribute then
begin
lAsLowerCase := MVCNameCaseAttribute(lAttr).KeyCase = ncLowerCase;
break;
end;
end;
if lAsLowerCase then
begin
lEntity.Id := lJSON.I['id'];
lEntity.Code := lJSON.I['code'];
lEntity.Name := lJSON.S['name'];
end
else
begin
// as is (upper case is not supported by the custom type serializer)
lEntity.Id := lJSON.I['Id'];
lEntity.Code := lJSON.I['Code'];
lEntity.Name := lJSON.S['Name'];
end;
end;
procedure TMVCEntityCustomSerializerJsonDataObjects.Serialize(
const AElementValue: TValue; var ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>);
@ -1206,6 +1313,38 @@ begin
end;
end;
{ TMVCNullableIntegerSerializerJsonDataObjects }
procedure TMVCNullableIntegerSerializerJsonDataObjects.DeserializeAttribute(
var AElementValue: TValue; const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
begin
end;
procedure TMVCNullableIntegerSerializerJsonDataObjects.DeserializeRoot(
const ASerializerObject, AObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
begin
end;
procedure TMVCNullableIntegerSerializerJsonDataObjects.SerializeAttribute(
const AElementValue: TValue; const APropertyName: string;
const ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
begin
end;
procedure TMVCNullableIntegerSerializerJsonDataObjects.SerializeRoot(
const AObject: TObject; out ASerializerObject: TObject;
const AAttributes: System.TArray<System.TCustomAttribute>);
begin
end;
initialization
TDUnitX.RegisterTestFixture(TMVCTestSerializerJsonDataObjects);