ADDED an action which uses a custom serializer in sample "renders.dproj"

NEW the JsonDataObjects based serializer is the default serializer
FIX Rendering a nil value, will result in a "null" json (with the json serializers)
This commit is contained in:
Daniele Teti 2017-05-18 00:02:22 +02:00
parent 9d0ab1cf45
commit ff1bc73949
13 changed files with 368 additions and 52 deletions

View File

@ -0,0 +1,92 @@
// ***************************************************************************
//
// Delphi MVC Framework
//
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
//
// https://github.com/danieleteti/delphimvcframework
//
// Collaborators with this file: Ezequiel Juliano Müller (ezequieljuliano@gmail.com)
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ***************************************************************************
unit CustomTypesSerializersU;
interface
uses
MVCFramework.Serializer.Intf,
System.Rtti;
type
// Custom serializer for TUserRoles type
TUserRolesSerializer = class(TInterfacedObject, IMVCTypeSerializer)
public
procedure Serialize(
const AElementValue: TValue;
var ASerializerObject: TObject;
const AAttributes: TArray<TCustomAttribute>
);
procedure Deserialize(
const ASerializedObject: TObject;
var AElementValue: TValue;
const AAttributes: TArray<TCustomAttribute>
);
end;
implementation
uses
JsonDataObjects, CustomTypesU;
{ TUserPasswordSerializer }
procedure TUserRolesSerializer.Deserialize(const ASerializedObject: TObject;
var AElementValue: TValue; const AAttributes: TArray<TCustomAttribute>);
begin
// todo: if you need, implement the deserilize method
end;
procedure TUserRolesSerializer.Serialize(const AElementValue: TValue;
var ASerializerObject: TObject; const AAttributes: TArray<TCustomAttribute>);
var
lJSONArr: TJDOJsonArray;
lRole: string;
I: Integer;
begin
{ Here I want to serialize the userroles array as json array }
// I know that the selected serializer uses JsonDataObject as serialization engine.
// You have to check the serializer documentation to find out what are the
// correct objects to create here!
lJSONArr := TJDOJsonArray.Create;
// Assign to the var parameter the correct object
ASerializerObject := lJSONArr;
// Then fill the returned object with the correct values
// reading from the AElementValue
lJSONArr.Add('--begin--'); { just to prove that the custom serializaion happends }
for I := 0 to AElementValue.GetArrayLength - 1 do
begin
lRole := AElementValue.GetArrayElement(i).AsString;
lJSONArr.Add(lRole);
end;
lJSONArr.Add('--end--'); { just to prove that the custom serializaion happends }
end;
end.

View File

@ -0,0 +1,74 @@
// ***************************************************************************
//
// Delphi MVC Framework
//
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
//
// https://github.com/danieleteti/delphimvcframework
//
// Collaborators with this file: Ezequiel Juliano Müller (ezequieljuliano@gmail.com)
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ***************************************************************************
unit CustomTypesU;
interface
type
// custom serialization is by-type so we define a type alias
// useful to identify all the fields that must be serialized
// using the custom serializer defined for this type
TUserRoles = TArray<string>;
// This is the main object which uses the
// custom serialized type as property Roles
TSysUser = class
private
FUserName: string;
FRoles: TUserRoles;
procedure SetUserName(const Value: string);
function GetUserRoles: TUserRoles;
public
constructor Create(aUserName: string; aRoles: TUserRoles);
property UserName: string read FUserName write SetUserName;
// Here we are using the custom-serialized type TUserRoles
property Roles: TUserRoles read GetUserRoles;
end;
implementation
{ TSysUser }
constructor TSysUser.Create(aUserName: string; aRoles: TUserRoles);
begin
inherited Create;
FUserName := aUserName;
FRoles := aRoles;
end;
function TSysUser.GetUserRoles: TUserRoles;
begin
Result := FRoles;
end;
procedure TSysUser.SetUserName(const Value: string);
begin
FUserName := Value;
end;
end.

View File

@ -1,3 +1,29 @@
// ***************************************************************************
//
// Delphi MVC Framework
//
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
//
// https://github.com/danieleteti/delphimvcframework
//
// Collaborators with this file: Ezequiel Juliano Müller (ezequieljuliano@gmail.com)
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ***************************************************************************
unit MyDataModuleU;
interface

View File

@ -1,11 +1,38 @@
unit RenderSampleControllerU;
// ***************************************************************************
//
// Delphi MVC Framework
//
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
//
// https://github.com/danieleteti/delphimvcframework
//
// Collaborators with this file: Ezequiel Juliano Müller (ezequieljuliano@gmail.com)
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ***************************************************************************
unit RenderSampleControllerU;
interface
uses
MVCFramework,
MVCFramework.Commons,
System.JSON;
MVCFramework.Serializer.Intf,
System.Rtti;
type
@ -78,20 +105,25 @@ type
[MVCPath('/exception')]
procedure RaiseException;
[MVCHTTPMethod([httpGET])]
[MVCPath('/customserializationtype')]
procedure GetCustomSerializationType;
end;
implementation
uses
BusinessObjectsU,
Data.DBXJSON,
Generics.Collections,
MVCFramework.DataSet.Utils,
MVCFramework.Serializer.Commons,
MyDataModuleU,
System.Classes,
System.SysUtils,
WebModuleU;
WebModuleU,
JsonDataObjects,
MVCFramework.TypesAliases, CustomTypesU;
{ TRoutingSampleController }
@ -177,6 +209,12 @@ begin
end;
end;
procedure TRenderSampleController.GetCustomSerializationType;
begin
// TSysUser contains a type with a custom serializer
Render(TSysUser.Create('daniele', ['poweruser', 'role1', 'role2']), True);
end;
procedure TRenderSampleController.GetPerson_AsHTML(CTX: TWebContext);
begin
ResponseStream

View File

@ -1,3 +1,29 @@
// ***************************************************************************
//
// Delphi MVC Framework
//
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
//
// https://github.com/danieleteti/delphimvcframework
//
// Collaborators with this file: Ezequiel Juliano Müller (ezequieljuliano@gmail.com)
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ***************************************************************************
unit WebModuleU;
interface
@ -25,16 +51,36 @@ implementation
{$R *.dfm}
uses RenderSampleControllerU, MVCFramework.Commons;
uses
MVCFramework.Commons, RenderSampleControllerU, CustomTypesU,
CustomTypesSerializersU,
MVCFramework.Serializer.JSON,
MVCFramework.Serializer.Intf,
System.Generics.Collections;
procedure TWebModule1.WebModuleCreate(Sender: TObject);
begin
DMVC := TMVCEngine.Create(self,
procedure(Config: TMVCConfig)
var
lX: TDictionary<string, IMVCSerializer>;
begin
Config[TMVCConfigKey.ViewPath] := 'templates';
end);
// Now the default json serializer is set, but how to set a different
// serializer? Check the lines below!
// ------------------------------------
// DMVC
// .Serializers
// .AddOrSetValue(TMVCMediaType.APPLICATION_JSON, TMVCJSONSerializer.Create);
// ------------------------------------
DMVC.AddController(TRenderSampleController);
DMVC
.Serializers
.Items[TMVCMediaType.APPLICATION_JSON]
.RegisterTypeSerializer(TypeInfo(TUserRoles), TUserRolesSerializer.Create);
end;
end.

View File

@ -1,3 +1,29 @@
// ***************************************************************************
//
// Delphi MVC Framework
//
// Copyright (c) 2010-2017 Daniele Teti and the DMVCFramework Team
//
// https://github.com/danieleteti/delphimvcframework
//
// Collaborators with this file: Ezequiel Juliano Müller (ezequieljuliano@gmail.com)
//
// ***************************************************************************
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
// ***************************************************************************
program renders;
{$APPTYPE CONSOLE}
@ -8,10 +34,12 @@ uses
MVCFramework.Commons,
Web.WebReq,
Web.WebBroker,
WebModuleU in 'WebModuleU.pas' {WebModule1: TWebModule} ,
WebModuleU in 'WebModuleU.pas' {WebModule1: TWebModule},
RenderSampleControllerU in 'RenderSampleControllerU.pas',
BusinessObjectsU in '..\commons\BusinessObjectsU.pas',
MyDataModuleU in 'MyDataModuleU.pas' {MyDataModule: TDataModule};
MyDataModuleU in 'MyDataModuleU.pas' {MyDataModule: TDataModule},
CustomTypesU in 'CustomTypesU.pas',
CustomTypesSerializersU in 'CustomTypesSerializersU.pas';
{$R *.res}

View File

@ -206,6 +206,8 @@
<Form>MyDataModule</Form>
<DesignClass>TDataModule</DesignClass>
</DCCReference>
<DCCReference Include="CustomTypesU.pas"/>
<DCCReference Include="CustomTypesSerializersU.pas"/>
<None Include="ModelSupport_renders\default.txaPackage"/>
<None Include="ModelSupport_renders\default.txvpck"/>
<None Include="ModelSupport_renders\WebModuleU\default.txaPackage"/>

View File

@ -665,17 +665,17 @@ begin
begin
for Field in ADataSet.Fields do
begin
Name := GetNameAs(ADataSet.Owner, Field.Name, Field.FieldName);
name := GetNameAs(ADataSet.Owner, Field.Name, Field.FieldName);
if (IsIgnoredAttribute(AIgnoredFields, Name)) or (IsIgnoredComponent(ADataSet.Owner, Field.Name)) then
if (IsIgnoredAttribute(AIgnoredFields, name)) or (IsIgnoredComponent(ADataSet.Owner, Field.Name)) then
Continue;
case GetNameCase(ADataSet, ANameCase) of
ncLowerCase: Name := LowerCase(Field.FieldName);
ncUpperCase: Name := UpperCase(Field.FieldName);
ncLowerCase: name := LowerCase(Field.FieldName);
ncUpperCase: name := UpperCase(Field.FieldName);
end;
Jv := AJSONObject.Get(Name).JsonValue;
Jv := AJSONObject.Get(name).JsonValue;
if not Assigned(Jv) then
Continue;
@ -928,8 +928,8 @@ var
begin
Result := EmptyStr;
if not Assigned(AObject) then
Exit;
if AObject = nil then
Exit('null');
if AObject is TJSONValue then
Exit(TJSONValue(AObject).ToJSON);

View File

@ -44,7 +44,8 @@ uses
MVCFramework.Serializer.Abstract,
MVCFramework.Serializer.Commons,
MVCFramework.DuckTyping,
JsonDataObjects;
MVCFramework.TypesAliases,
JsonDataObjects {JsonDataObjects must be after MVCFramework.TypesAliases};
type
@ -56,7 +57,6 @@ type
public
constructor Create; overload;
constructor Create(const AValue: string); overload;
property Value: string read FValue write FValue;
end;
@ -642,14 +642,9 @@ begin
else
begin
// dt: if a key is null, jsondataobjects assign it the type jdtObject
if AJsonObject[AName].ObjectValue = nil then
begin
ChildObject := nil; // dt
end
else
if AJsonObject[AName].ObjectValue <> nil then
begin
ChildObject := AValue.AsObject;
if Assigned(ChildObject) then
JsonObjectToObject(AJsonObject.O[AName], ChildObject, GetSerializationType(ChildObject, AType), AIgnored);
end;
end;
@ -941,10 +936,13 @@ begin
Result := EmptyStr;
if not Assigned(AObject) then
Exit;
Exit('null');
if AObject is TJsonBaseObject then
Exit(TJsonBaseObject(AObject).ToJSON(False));
Exit(TJsonBaseObject(AObject).ToJSON(True));
if AObject is MVCFramework.TypesAliases.TJSONValue then
Exit(MVCFramework.TypesAliases.TJSONValue(AObject).ToJSON);
ObjType := GetRttiContext.GetType(AObject.ClassType);
if GetTypeSerializers.ContainsKey(ObjType.Handle) then

View File

@ -184,7 +184,7 @@ type
function GetParamAsInt64(const AParamName: string): Int64;
function GetFiles: TAbstractWebRequestFiles;
function GetParamNames: TArray<string>;
function GetParamsMulti(const AParamName: string): TArray<String>;
function GetParamsMulti(const AParamName: string): TArray<string>;
protected
{ protected declarations }
public
@ -221,7 +221,7 @@ type
property ParamsTable: TMVCRequestParamsTable read FParamsTable write FParamsTable;
property ParamNames: TArray<string> read GetParamNames;
property Params[const AParamName: string]: string read GetParams;
property ParamsMulti[const AParamName: string]: TArray<String> read GetParamsMulti;
property ParamsMulti[const AParamName: string]: TArray<string> read GetParamsMulti;
property ParamsAsInteger[const AParamName: string]: Integer read GetParamAsInteger;
property ParamsAsInt64[const AParamName: string]: Int64 read GetParamAsInt64;
property IsAjax: Boolean read GetIsAjax;
@ -564,7 +564,7 @@ type
FApplicationSession: TWebApplicationSession;
FSavedOnBeforeDispatch: THTTPMethodEvent;
function IsStaticFileRequest(const ARequest: TWebRequest; out AFileName: string): Boolean;
function SendStaticFileIfPresent(const AContext: TWebContext; const AFileName: String): Boolean;
function SendStaticFileIfPresent(const AContext: TWebContext; const AFileName: string): Boolean;
procedure FillActualParamsForAction(
const AContext: TWebContext;
const AActionFormalParams: TArray<TRttiParameter>;
@ -667,7 +667,7 @@ type
{ protected declarations }
public
constructor Create; overload;
constructor Create(AStatusCode: Integer; AReasonString: String; AMessage: String); overload;
constructor Create(AStatusCode: Integer; AReasonString: string; AMessage: string); overload;
destructor Destroy; override;
property StatusCode: Integer read FStatusCode write FStatusCode;
@ -690,7 +690,7 @@ type
protected
function GetRealFileName(const AViewName: string): string; virtual;
function IsCompiledVersionUpToDate(const AFileName, ACompiledFileName: string): Boolean; virtual; abstract;
procedure SetOutput(const AOutput: String);
procedure SetOutput(const AOutput: string);
public
constructor Create(
const AViewName: string;
@ -718,7 +718,8 @@ implementation
uses
MVCFramework.Router,
MVCFramework.SysControllers;
MVCFramework.SysControllers,
MVCFramework.Serializer.JsonDataObjects;
var
_IsShuttingDown: Int64 = 0;
@ -747,7 +748,7 @@ var
begin
Result := '';
for I := Low(TMVCHTTPMethodType) to High(TMVCHTTPMethodType) do
for I := low(TMVCHTTPMethodType) to high(TMVCHTTPMethodType) do
if I in FMVCHTTPMethods then
Result := Result + ',' + GetEnumName(TypeInfo(TMVCHTTPMethodType), Ord(I));
@ -1087,10 +1088,10 @@ begin
end;
function TMVCWebRequest.GetParamsMulti(
const AParamName: string): TArray<String>;
const AParamName: string): TArray<string>;
var
lList: TList<String>;
procedure AddParamsToList(const AStrings: TStrings; const AList: TList<String>);
lList: TList<string>;
procedure AddParamsToList(const AStrings: TStrings; const AList: TList<string>);
var
I: Integer;
begin
@ -1100,7 +1101,7 @@ var
end;
begin
lList := TList<String>.Create;
lList := TList<string>.Create;
try
AddParamsToList(FWebRequest.ContentFields, lList);
AddParamsToList(FWebRequest.QueryFields, lList);
@ -2056,7 +2057,11 @@ end;
procedure TMVCEngine.RegisterDefaultsSerializers;
begin
FSerializers.Add(TMVCMediaType.APPLICATION_JSON, TMVCJSONSerializer.Create);
if not FSerializers.ContainsKey(TMVCMediaType.APPLICATION_JSON) then
begin
FSerializers.Add(TMVCMediaType.APPLICATION_JSON, TMVCJSONDataObjectsSerializer.Create);
// FSerializers.Add(TMVCMediaType.APPLICATION_JSON, TMVCJSONSerializer.Create);
end;
end;
procedure TMVCEngine.ResponseErrorPage(const AException: Exception; const ARequest: TWebRequest; const AResponse: TWebResponse);
@ -2098,7 +2103,7 @@ begin
Result := ASessionId;
end;
function TMVCEngine.SendStaticFileIfPresent(const AContext: TWebContext; const AFileName: String): Boolean;
function TMVCEngine.SendStaticFileIfPresent(const AContext: TWebContext; const AFileName: string): Boolean;
var
LContentType: string;
begin
@ -2486,17 +2491,12 @@ end;
procedure TMVCController.Render(const AObject: TObject; const AOwns: Boolean; const AType: TMVCSerializationType);
begin
if Assigned(AObject) then
begin
try
Render(Serializer(ContentType).SerializeObject(AObject, AType));
finally
if AOwns then
AObject.Free;
end;
end
else
raise EMVCException.Create('Can not render an empty object.');
end;
procedure TMVCController.Render(const AStream: TStream; const AOwns: Boolean);
@ -2770,7 +2770,7 @@ begin
end;
constructor TMVCErrorResponse.Create(AStatusCode: Integer; AReasonString,
AMessage: String);
AMessage: string);
begin
Create;
StatusCode := AStatusCode;
@ -2839,7 +2839,7 @@ begin
Result := EmptyStr;
end;
procedure TMVCBaseViewEngine.SetOutput(const AOutput: String);
procedure TMVCBaseViewEngine.SetOutput(const AOutput: string);
begin
FOutput := AOutput;
end;

View File

@ -56,7 +56,7 @@ begin
MVCEngine := TMVCEngine.Create(self,
procedure(Config: TMVCConfig)
begin
//no config here
// no config here
end, nil);
MVCEngine.AddController(TTestServerController)
.AddController(TTestPrivateServerController)

View File

@ -54,6 +54,7 @@ type
published
{ serialize declarations }
procedure TestSerializeEntity;
procedure TestSerializeNil;
procedure TestSerializeEntityUpperCaseNames;
procedure TestSerializeEntityLowerCaseNames;
procedure TestSerializeEntityNameAs;
@ -1032,6 +1033,11 @@ begin
end;
end;
procedure TMVCTestSerializerJsonDataObjects.TestSerializeNil;
begin
CheckEquals('null', FSerializer.SerializeObject(nil));
end;
{ TMVCEntityCustomSerializerJsonDataObjects }
procedure TMVCEntityCustomSerializerJsonDataObjects.Deserialize(

View File

@ -54,6 +54,7 @@ type
published
{ serialize declarations }
procedure TestSerializeEntity;
procedure TestSerializeNill;
procedure TestSerializeEntityUpperCaseNames;
procedure TestSerializeEntityLowerCaseNames;
procedure TestSerializeEntityNameAs;
@ -1028,6 +1029,11 @@ begin
end;
end;
procedure TMVCTestSerializerJSON.TestSerializeNill;
begin
CheckEquals('null', FSerializer.SerializeObject(nil));
end;
{ TMVCEntityCustomSerializerJSON }
procedure TMVCEntityCustomSerializerJSON.Deserialize(