mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 15:55:54 +01:00
Completed refactoring about IMVCTypeSerializer
This commit is contained in:
parent
132e169542
commit
7ca4ccbe59
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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(
|
||||
|
@ -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.
|
||||
|
@ -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]);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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}
|
||||
|
||||
|
@ -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>
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user