mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 15:55:54 +01:00
New! Added the new MVCOwned
attribute which allows to auto-create nested objects in the deserialization phase. This will not change the current behavior, you ned to explocitly define a property (or a field) as MVCOwned
to allows the serialization to create or destroy object for you.
This commit is contained in:
parent
6837182cc3
commit
4986d9ba3f
@ -423,6 +423,10 @@ This version introduced new features in many different areas (swagger, server si
|
|||||||
|
|
||||||
## Next Release: 3.2.2-nitrogen ("repo" version)
|
## Next Release: 3.2.2-nitrogen ("repo" version)
|
||||||
|
|
||||||
|
The current beta release is named 3.2.2-nitrogen. If you want to stay on the-edge or just help the testers, clone the repo and start using it. Be warned: it may contains unstable code.
|
||||||
|
|
||||||
|
### Whet's new in 3.2.2-nitrogen (currently in beta)
|
||||||
|
|
||||||
- ⚡New `TMVCRESTClient` implementation based on *Net components, the previous one was based on INDY Components (thanks to [João Antônio Duarte](https://github.com/joaoduarte19)).
|
- ⚡New `TMVCRESTClient` implementation based on *Net components, the previous one was based on INDY Components (thanks to [João Antônio Duarte](https://github.com/joaoduarte19)).
|
||||||
|
|
||||||
- ⚡New! `MVCJSONRPCAllowGET` attribute allows a remote JSON-RPC published object, or a specific method, to be called using GET HTTP Verb as well as POST HTTP Verb. POST is always available, GET is available only if explicitly allowed. `IMVCJSONRPCExecutor` allows to specify which HTTP Verb to use when call the server JSON.RPC methods. The default verb can be injected in the constructor and each `ExecuteRequest`/`ExecuteNotification` allows to override od adhere to the instance default.
|
- ⚡New! `MVCJSONRPCAllowGET` attribute allows a remote JSON-RPC published object, or a specific method, to be called using GET HTTP Verb as well as POST HTTP Verb. POST is always available, GET is available only if explicitly allowed. `IMVCJSONRPCExecutor` allows to specify which HTTP Verb to use when call the server JSON.RPC methods. The default verb can be injected in the constructor and each `ExecuteRequest`/`ExecuteNotification` allows to override od adhere to the instance default.
|
||||||
@ -451,6 +455,8 @@ This version introduced new features in many different areas (swagger, server si
|
|||||||
|
|
||||||
- ⚡New! Added new default parameter to `TMVCActiveRecord.RemoveDefaultConnection` and `TMVCActiveRecord.RemoveConnection` to avoid exceptions in case of not initialized connection.
|
- ⚡New! Added new default parameter to `TMVCActiveRecord.RemoveDefaultConnection` and `TMVCActiveRecord.RemoveConnection` to avoid exceptions in case of not initialized connection.
|
||||||
|
|
||||||
|
- ⚡New! Added the new `MVCOwned` attribute which allows to auto-create nested objects in the deserialization phase. This will not change the current behavior, you ned to explocitly define a property (or a field) as `MVCOwned` to allows the serialization to create or destroy object for you.
|
||||||
|
|
||||||
- ⚡New! Added `TMVCJWTBlackListMiddleware` to allow black-listing and (a sort of) logout for a JWT based authentication. This middleware **must** be registered **after** the `TMVCJWTAuthenticationMiddleware`.
|
- ⚡New! Added `TMVCJWTBlackListMiddleware` to allow black-listing and (a sort of) logout for a JWT based authentication. This middleware **must** be registered **after** the `TMVCJWTAuthenticationMiddleware`.
|
||||||
|
|
||||||
> This middleware provides 2 events named: `OnAcceptToken` (invoked when a request contains a token - need to returns true/false if the token is still accepted by the server or not) and `OnNewJWTToBlackList` (invoked when a client ask to blacklist its current token). There is a new sample available which shows the funtionalities: `samples\middleware_jwtblacklist`.
|
> This middleware provides 2 events named: `OnAcceptToken` (invoked when a request contains a token - need to returns true/false if the token is still accepted by the server or not) and `OnNewJWTToBlackList` (invoked when a client ask to blacklist its current token). There is a new sample available which shows the funtionalities: `samples\middleware_jwtblacklist`.
|
||||||
|
@ -268,6 +268,28 @@ type
|
|||||||
property Skills: string read FSkills write SetSkills;
|
property Skills: string read FSkills write SetSkills;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
[MVCNameCase(ncLowerCase)]
|
||||||
|
TProgrammerEx = class(TProgrammer)
|
||||||
|
private
|
||||||
|
[MVCOwned] //required only for field serialization
|
||||||
|
FMentor: TProgrammerEx;
|
||||||
|
public
|
||||||
|
destructor Destroy; override;
|
||||||
|
[MVCOwned] //required only for property serialization
|
||||||
|
property Mentor: TProgrammerEx read FMentor write fMentor;
|
||||||
|
end;
|
||||||
|
|
||||||
|
[MVCNameCase(ncLowerCase)]
|
||||||
|
TProgrammerEx2 = class(TProgrammer)
|
||||||
|
private
|
||||||
|
FMentor: TProgrammer;
|
||||||
|
public
|
||||||
|
destructor Destroy; override;
|
||||||
|
[MVCOwned(TProgrammerEx2)]
|
||||||
|
property Mentor: TProgrammer read FMentor write fMentor;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
[MVCNameCase(ncLowerCase)]
|
[MVCNameCase(ncLowerCase)]
|
||||||
TPhilosopher = class(TPerson)
|
TPhilosopher = class(TPerson)
|
||||||
private
|
private
|
||||||
@ -659,6 +681,22 @@ begin
|
|||||||
fPeople := Value;
|
fPeople := Value;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ TProgrammerEx }
|
||||||
|
|
||||||
|
destructor TProgrammerEx.Destroy;
|
||||||
|
begin
|
||||||
|
FMentor.Free;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
|
{ TProgrammerEx2 }
|
||||||
|
|
||||||
|
destructor TProgrammerEx2.Destroy;
|
||||||
|
begin
|
||||||
|
FMentor.Free;
|
||||||
|
inherited;
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
|
||||||
Randomize;
|
Randomize;
|
||||||
|
@ -185,6 +185,15 @@ type
|
|||||||
property MappedValues: TList<string> read FMappedValues;
|
property MappedValues: TList<string> read FMappedValues;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
MVCOwnedAttribute = class(TCustomAttribute)
|
||||||
|
private
|
||||||
|
fClassRef: TClass;
|
||||||
|
public
|
||||||
|
constructor Create(const ClassRef: TClass = nil);
|
||||||
|
property ClassRef: TClass read fClassRef;
|
||||||
|
end;
|
||||||
|
|
||||||
TMVCSerializerHelper = record
|
TMVCSerializerHelper = record
|
||||||
private
|
private
|
||||||
{ private declarations }
|
{ private declarations }
|
||||||
@ -214,7 +223,7 @@ type
|
|||||||
class function StringToTypeKind(const AValue: string): TTypeKind; static;
|
class function StringToTypeKind(const AValue: string): TTypeKind; static;
|
||||||
class function CreateObject(const AObjectType: TRttiType): TObject; overload; static;
|
class function CreateObject(const AObjectType: TRttiType): TObject; overload; static;
|
||||||
class function CreateObject(const AQualifiedClassName: string): 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; inline;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TMVCLinksCallback = reference to procedure(const Links: TMVCStringDictionary);
|
TMVCLinksCallback = reference to procedure(const Links: TMVCStringDictionary);
|
||||||
@ -1731,6 +1740,14 @@ begin
|
|||||||
inherited;
|
inherited;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
{ MVCOwnedAttribute }
|
||||||
|
|
||||||
|
constructor MVCOwnedAttribute.Create(const ClassRef: TClass);
|
||||||
|
begin
|
||||||
|
inherited Create;
|
||||||
|
fClassRef := ClassRef;
|
||||||
|
end;
|
||||||
|
|
||||||
initialization
|
initialization
|
||||||
|
|
||||||
gLocalTimeStampAsUTC := False;
|
gLocalTimeStampAsUTC := False;
|
||||||
|
@ -92,7 +92,8 @@ type
|
|||||||
function TryNullableToJSON(const AValue: TValue; const AJsonObject: TJDOJsonObject; const AName: string): Boolean;
|
function TryNullableToJSON(const AValue: TValue; const AJsonObject: TJDOJsonObject; const AName: string): Boolean;
|
||||||
procedure JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
procedure JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
||||||
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
||||||
procedure JsonDataValueToAttribute(const AJsonObject: TJDOJsonObject; const AName: string; var AValue: TValue;
|
procedure JsonDataValueToAttribute(const AObject: TObject; const ARttiMember: TRttiMember;
|
||||||
|
const AJsonObject: TJDOJsonObject; const AName: string; var AValue: TValue;
|
||||||
const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
|
const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
|
||||||
const ACustomAttributes: TArray<TCustomAttribute>);
|
const ACustomAttributes: TArray<TCustomAttribute>);
|
||||||
procedure JsonArrayToList(const AJsonArray: TJDOJsonArray; const AList: IMVCList; const AClazz: TClass;
|
procedure JsonArrayToList(const AJsonArray: TJDOJsonArray; const AList: IMVCList; const AClazz: TClass;
|
||||||
@ -1098,14 +1099,18 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMVCJsonDataObjectsSerializer.JsonDataValueToAttribute(const AJsonObject: TJDOJsonObject; const AName: string;
|
procedure TMVCJsonDataObjectsSerializer.JsonDataValueToAttribute(
|
||||||
var AValue: TValue; const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
|
const AObject: TObject;
|
||||||
const ACustomAttributes: TArray<TCustomAttribute>);
|
const ARttiMember: TRttiMember;
|
||||||
|
const AJsonObject: TJDOJsonObject;
|
||||||
|
const AName: string; var AValue: TValue; const AType: TMVCSerializationType;
|
||||||
|
const AIgnored: TMVCIgnoredList; const ACustomAttributes: TArray<TCustomAttribute>);
|
||||||
var
|
var
|
||||||
ChildObject: TObject;
|
ChildObject: TObject;
|
||||||
ChildList: IMVCList;
|
ChildList: IMVCList;
|
||||||
ChildListOfAtt: MVCListOfAttribute;
|
ChildListOfAtt: MVCListOfAttribute;
|
||||||
LEnumAsAttr: MVCEnumSerializationAttribute;
|
LEnumAsAttr: MVCEnumSerializationAttribute;
|
||||||
|
lOwnedAttribute: MVCOwnedAttribute;
|
||||||
LEnumMappedValues: TList<string>;
|
LEnumMappedValues: TList<string>;
|
||||||
LEnumSerType: TMVCEnumSerializationType;
|
LEnumSerType: TMVCEnumSerializationType;
|
||||||
LClazz: TClass;
|
LClazz: TClass;
|
||||||
@ -1113,17 +1118,85 @@ var
|
|||||||
lOutInteger: Integer;
|
lOutInteger: Integer;
|
||||||
lOutInteger64: Int64;
|
lOutInteger64: Int64;
|
||||||
lTypeInfo: PTypeInfo;
|
lTypeInfo: PTypeInfo;
|
||||||
|
lJSONExists: Boolean;
|
||||||
|
lJSONIsNull: Boolean;
|
||||||
|
lChildObjectAssigned: Boolean;
|
||||||
begin
|
begin
|
||||||
|
ChildObject := nil;
|
||||||
lTypeInfo := AValue.TypeInfo;
|
lTypeInfo := AValue.TypeInfo;
|
||||||
if AValue.Kind in [tkClass, tkInterface] then
|
if AValue.Kind in [tkClass, tkInterface] then
|
||||||
begin
|
begin
|
||||||
ChildObject := nil;
|
if not AValue.IsEmpty then
|
||||||
if not AValue.IsEmpty and (AValue.Kind = tkInterface) then
|
begin
|
||||||
|
if AValue.Kind = tkInterface then
|
||||||
ChildObject := TObject(AValue.AsInterface)
|
ChildObject := TObject(AValue.AsInterface)
|
||||||
else if AValue.Kind = tkClass then
|
else
|
||||||
ChildObject := AValue.AsObject;
|
ChildObject := AValue.AsObject;
|
||||||
|
end;
|
||||||
|
|
||||||
if Assigned(ChildObject) then
|
if Assigned(ChildObject) then
|
||||||
|
begin
|
||||||
|
lTypeInfo := ChildObject.ClassInfo
|
||||||
|
end;
|
||||||
|
|
||||||
|
if TMVCSerializerHelper.AttributeExists<MVCOwnedAttribute>(ACustomAttributes, lOwnedAttribute) then
|
||||||
|
begin
|
||||||
|
{ Now, can happens the following situations:
|
||||||
|
|
||||||
|
ChildObject JSON Outcome
|
||||||
|
----------- --------- ----------------------------------------------------
|
||||||
|
1) Created Exists The JSON is loaded in the object (default)
|
||||||
|
2) Created NotExists Leave unchanged
|
||||||
|
3) Created is Null If ChildObject is Owned must be destroyed
|
||||||
|
4) nil Exists If ChildObject is Owned, create it and load the json
|
||||||
|
5) nil NotExists Leave unchanged
|
||||||
|
6) nil is Null Leave unchanged
|
||||||
|
|
||||||
|
|
||||||
|
--> So, we'll manage only case 3 and 4 <--
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
lJSONExists := AJsonObject.Contains(AName);
|
||||||
|
lJSONIsNull := lJSONExists and AJsonObject.IsNull(AName);
|
||||||
|
lChildObjectAssigned := ChildObject <> nil;
|
||||||
|
|
||||||
|
//case 3
|
||||||
|
if lChildObjectAssigned and lJSONIsNull then
|
||||||
|
begin
|
||||||
|
ChildObject.Free;
|
||||||
|
case AType of
|
||||||
|
stUnknown, stDefault, stProperties:
|
||||||
|
TRttiProperty(ARttiMember).SetValue(AObject, nil);
|
||||||
|
stFields:
|
||||||
|
TRttiField(ARttiMember).SetValue(AObject, nil);
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
//case 4
|
||||||
|
else if (not lChildObjectAssigned) and lJSONExists and (not lJSONIsNull) then
|
||||||
|
begin
|
||||||
|
if lOwnedAttribute.ClassRef <> nil then
|
||||||
|
begin
|
||||||
|
ChildObject := TMVCSerializerHelper.CreateObject(lOwnedAttribute.ClassRef.QualifiedClassName);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
case AType of
|
||||||
|
stUnknown, stDefault, stProperties:
|
||||||
|
ChildObject := TMVCSerializerHelper.CreateObject(TRttiProperty(ARttiMember).PropertyType);
|
||||||
|
stFields:
|
||||||
|
ChildObject := TMVCSerializerHelper.CreateObject(TRttiField(ARttiMember).FieldType);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
lTypeInfo := ChildObject.ClassInfo;
|
lTypeInfo := ChildObject.ClassInfo;
|
||||||
|
case AType of
|
||||||
|
stUnknown, stDefault, stProperties:
|
||||||
|
TRttiProperty(ARttiMember).SetValue(AObject, ChildObject);
|
||||||
|
stFields:
|
||||||
|
TRttiField(ARttiMember).SetValue(AObject, ChildObject);
|
||||||
|
end;
|
||||||
|
end; //end cases
|
||||||
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
if GetTypeSerializers.ContainsKey(lTypeInfo) then
|
if GetTypeSerializers.ContainsKey(lTypeInfo) then
|
||||||
@ -1325,13 +1398,13 @@ begin
|
|||||||
case AValue.Kind of
|
case AValue.Kind of
|
||||||
tkInterface:
|
tkInterface:
|
||||||
begin
|
begin
|
||||||
ChildObject := TObject(AValue.AsInterface);
|
//ChildObject := TObject(AValue.AsInterface);
|
||||||
JsonObjectToObject(AJsonObject.O[AName], ChildObject, GetSerializationType(ChildObject, AType),
|
JsonObjectToObject(AJsonObject.O[AName], ChildObject, GetSerializationType(ChildObject, AType),
|
||||||
AIgnored);
|
AIgnored);
|
||||||
end;
|
end;
|
||||||
tkClass:
|
tkClass:
|
||||||
begin
|
begin
|
||||||
ChildObject := AValue.AsObject;
|
//ChildObject := AValue.AsObject;
|
||||||
JsonObjectToObject(AJsonObject.O[AName], ChildObject, GetSerializationType(ChildObject, AType),
|
JsonObjectToObject(AJsonObject.O[AName], ChildObject, GetSerializationType(ChildObject, AType),
|
||||||
AIgnored);
|
AIgnored);
|
||||||
end;
|
end;
|
||||||
@ -1511,8 +1584,9 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TMVCJsonDataObjectsSerializer.JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
procedure TMVCJsonDataObjectsSerializer.JsonObjectToObject(const AJsonObject: TJDOJsonObject;
|
||||||
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
const AObject: TObject; const AType: TMVCSerializationType;
|
||||||
|
const AIgnoredAttributes: TMVCIgnoredList);
|
||||||
var
|
var
|
||||||
lObjType: TRttiType;
|
lObjType: TRttiType;
|
||||||
lProp: TRttiProperty;
|
lProp: TRttiProperty;
|
||||||
@ -1558,7 +1632,9 @@ begin
|
|||||||
begin
|
begin
|
||||||
lAttributeValue := lProp.GetValue(AObject);
|
lAttributeValue := lProp.GetValue(AObject);
|
||||||
lKeyName := TMVCSerializerHelper.GetKeyName(lProp, lObjType);
|
lKeyName := TMVCSerializerHelper.GetKeyName(lProp, lObjType);
|
||||||
JsonDataValueToAttribute(AJsonObject, lKeyName, lAttributeValue, AType, AIgnoredAttributes,
|
JsonDataValueToAttribute(
|
||||||
|
AObject, lProp,
|
||||||
|
AJsonObject, lKeyName, lAttributeValue, AType, AIgnoredAttributes,
|
||||||
lProp.GetAttributes);
|
lProp.GetAttributes);
|
||||||
if (not lAttributeValue.IsEmpty) and (not lAttributeValue.IsObject) and lProp.IsWritable then
|
if (not lAttributeValue.IsEmpty) and (not lAttributeValue.IsObject) and lProp.IsWritable then
|
||||||
begin
|
begin
|
||||||
@ -1592,9 +1668,12 @@ begin
|
|||||||
begin
|
begin
|
||||||
lAttributeValue := lFld.GetValue(AObject);
|
lAttributeValue := lFld.GetValue(AObject);
|
||||||
lKeyName := TMVCSerializerHelper.GetKeyName(lFld, lObjType);
|
lKeyName := TMVCSerializerHelper.GetKeyName(lFld, lObjType);
|
||||||
JsonDataValueToAttribute(AJsonObject, lKeyName, lAttributeValue, AType, AIgnoredAttributes,
|
JsonDataValueToAttribute(
|
||||||
lFld.GetAttributes);
|
AObject, lFld,
|
||||||
if not lAttributeValue.IsEmpty then
|
AJsonObject, lKeyName,
|
||||||
|
lAttributeValue, AType,
|
||||||
|
AIgnoredAttributes, lFld.GetAttributes);
|
||||||
|
if (not lAttributeValue.IsEmpty) and (not lAttributeValue.IsObject) then
|
||||||
lFld.SetValue(AObject, lAttributeValue);
|
lFld.SetValue(AObject, lAttributeValue);
|
||||||
end;
|
end;
|
||||||
except
|
except
|
||||||
|
@ -219,6 +219,7 @@
|
|||||||
</DCCReference>
|
</DCCReference>
|
||||||
<DCCReference Include="..\..\..\sources\MVCFramework.Commons.pas"/>
|
<DCCReference Include="..\..\..\sources\MVCFramework.Commons.pas"/>
|
||||||
<DCCReference Include="..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas"/>
|
<DCCReference Include="..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas"/>
|
||||||
|
<DCCReference Include="..\..\..\sources\MVCFramework.SQLGenerators.Firebird.pas"/>
|
||||||
<BuildConfiguration Include="Base">
|
<BuildConfiguration Include="Base">
|
||||||
<Key>Base</Key>
|
<Key>Base</Key>
|
||||||
</BuildConfiguration>
|
</BuildConfiguration>
|
||||||
|
@ -58,7 +58,6 @@ type
|
|||||||
|
|
||||||
{ serialize declarations }
|
{ serialize declarations }
|
||||||
[Test]
|
[Test]
|
||||||
// [Category('this')]
|
|
||||||
procedure TestSerializeAllTypes;
|
procedure TestSerializeAllTypes;
|
||||||
[Test]
|
[Test]
|
||||||
procedure TestSerializeDateTimeProperty;
|
procedure TestSerializeDateTimeProperty;
|
||||||
@ -73,7 +72,6 @@ type
|
|||||||
[Test]
|
[Test]
|
||||||
procedure TestSerializeEntityUpperCaseNames;
|
procedure TestSerializeEntityUpperCaseNames;
|
||||||
[Test]
|
[Test]
|
||||||
// [Category('this')]
|
|
||||||
procedure TestSerializeEntityWithArray;
|
procedure TestSerializeEntityWithArray;
|
||||||
[Test]
|
[Test]
|
||||||
procedure TestSerializeEntityLowerCaseNames;
|
procedure TestSerializeEntityLowerCaseNames;
|
||||||
@ -139,6 +137,38 @@ type
|
|||||||
[Test]
|
[Test]
|
||||||
[Category('serializers')]
|
[Category('serializers')]
|
||||||
procedure TestSerializeListWithNulls2;
|
procedure TestSerializeListWithNulls2;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Category('serializers')]
|
||||||
|
procedure TestDeserializeOwnedProperty_WithPropertyUnassigned_JSONExists;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Category('serializers')]
|
||||||
|
procedure TestDeserializeOwnedProperty_WithPropertyAssigned_JSONExists;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Category('serializers')]
|
||||||
|
procedure TestDeserializeOwnedProperty_WithPropertyAssigned_JSONNull;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Category('serializers')]
|
||||||
|
procedure TestDeserializeOwnedProperty_WithPropertyAssigned_JSONNotExists;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Category('serializers')]
|
||||||
|
procedure TestDeserializeOwnedProperty_WithPropertyUnAssigned_JSONNull;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Category('serializers')]
|
||||||
|
procedure TestDeserializeOwnedProperty_WithFieldsUnassigned_JSONExists;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Category('serializers')]
|
||||||
|
procedure TestDeserializeOwnedField_WithFieldsAssigned_JSONNull;
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
[Category('serializers')]
|
||||||
|
procedure TestDeserializeOwnedProperty_WithPropertyUnassigned_JSONExists_Polimorphic;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
TMVCEntityCustomSerializerJsonDataObjects = class(TInterfacedObject, IMVCTypeSerializer)
|
TMVCEntityCustomSerializerJsonDataObjects = class(TInterfacedObject, IMVCTypeSerializer)
|
||||||
@ -578,6 +608,244 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeOwnedProperty_WithPropertyUnassigned_JSONExists;
|
||||||
|
const
|
||||||
|
lJSON = '{' +
|
||||||
|
' "skills": "",' +
|
||||||
|
' "id": 2,' +
|
||||||
|
' "firstname": "child firstname",' +
|
||||||
|
' "lastname": "child lastname",' +
|
||||||
|
' "dob": null,' +
|
||||||
|
' "married": false,' +
|
||||||
|
' "mentor": { ' +
|
||||||
|
' "mentor": null, ' +
|
||||||
|
' "skills": "superb programmer", ' +
|
||||||
|
' "firstname": "mentor firstname", ' +
|
||||||
|
' "lastname": "mentor lasttname", ' +
|
||||||
|
' "dob": null, ' +
|
||||||
|
' "married": false, ' +
|
||||||
|
' "id": 2 ' +
|
||||||
|
' }' +
|
||||||
|
' }';
|
||||||
|
var
|
||||||
|
lProgrammerEx: TProgrammerEx;
|
||||||
|
begin
|
||||||
|
lProgrammerEx := TProgrammerEx.Create;
|
||||||
|
try
|
||||||
|
fSerializer.DeserializeObject(lJSON, lProgrammerEx);
|
||||||
|
Assert.AreEqual('child firstname', lProgrammerEx.FirstName);
|
||||||
|
Assert.IsNotNull(lProgrammerEx.Mentor);
|
||||||
|
Assert.IsNull(lProgrammerEx.Mentor.Mentor);
|
||||||
|
Assert.AreEqual('mentor firstname', lProgrammerEx.Mentor.FirstName);
|
||||||
|
finally
|
||||||
|
lProgrammerEx.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeOwnedProperty_WithPropertyUnassigned_JSONExists_Polimorphic;
|
||||||
|
const
|
||||||
|
lJSON = '{' +
|
||||||
|
' "skills": "",' +
|
||||||
|
' "id": 2,' +
|
||||||
|
' "firstname": "child firstname",' +
|
||||||
|
' "lastname": "child lastname",' +
|
||||||
|
' "dob": null,' +
|
||||||
|
' "married": false,' +
|
||||||
|
' "mentor": { ' +
|
||||||
|
' "mentor": null, ' +
|
||||||
|
' "skills": "superb programmer", ' +
|
||||||
|
' "firstname": "mentor firstname", ' +
|
||||||
|
' "lastname": "mentor lasttname", ' +
|
||||||
|
' "dob": null, ' +
|
||||||
|
' "married": false, ' +
|
||||||
|
' "id": 2 ' +
|
||||||
|
' }' +
|
||||||
|
' }';
|
||||||
|
var
|
||||||
|
lProgrammerEx: TProgrammerEx2;
|
||||||
|
begin
|
||||||
|
lProgrammerEx := TProgrammerEx2.Create;
|
||||||
|
try
|
||||||
|
fSerializer.DeserializeObject(lJSON, lProgrammerEx);
|
||||||
|
Assert.AreEqual('child firstname', lProgrammerEx.FirstName);
|
||||||
|
Assert.IsNotNull(lProgrammerEx.Mentor);
|
||||||
|
Assert.IsTrue(lProgrammerEx.Mentor is TProgrammerEx2, lProgrammerEx.Mentor.ClassName);
|
||||||
|
Assert.AreEqual('mentor firstname', lProgrammerEx.Mentor.FirstName);
|
||||||
|
finally
|
||||||
|
lProgrammerEx.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeOwnedProperty_WithPropertyUnAssigned_JSONNull;
|
||||||
|
const
|
||||||
|
lJSON = '{' +
|
||||||
|
' "skills": "",' +
|
||||||
|
' "id": 2,' +
|
||||||
|
' "firstname": "child firstname",' +
|
||||||
|
' "lastname": "child lastname",' +
|
||||||
|
' "dob": null,' +
|
||||||
|
' "married": false,' +
|
||||||
|
' "mentor": null ' +
|
||||||
|
' }';
|
||||||
|
var
|
||||||
|
lProgrammerEx: TProgrammerEx;
|
||||||
|
begin
|
||||||
|
lProgrammerEx := TProgrammerEx.Create;
|
||||||
|
try
|
||||||
|
fSerializer.DeserializeObject(lJSON, lProgrammerEx);
|
||||||
|
Assert.AreEqual('child firstname', lProgrammerEx.FirstName);
|
||||||
|
Assert.IsNull(lProgrammerEx.Mentor);
|
||||||
|
finally
|
||||||
|
lProgrammerEx.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeOwnedField_WithFieldsAssigned_JSONNull;
|
||||||
|
const
|
||||||
|
lJSON = '{' +
|
||||||
|
' "fskills": "",' +
|
||||||
|
' "fid": 2,' +
|
||||||
|
' "ffirstname": "child firstname",' +
|
||||||
|
' "flastname": "child lastname",' +
|
||||||
|
' "fdob": null,' +
|
||||||
|
' "fmarried": false,' +
|
||||||
|
' "fmentor": null ' +
|
||||||
|
' }';
|
||||||
|
var
|
||||||
|
lProgrammerEx: TProgrammerEx;
|
||||||
|
begin
|
||||||
|
lProgrammerEx := TProgrammerEx.Create;
|
||||||
|
try
|
||||||
|
lProgrammerEx.Mentor := TProgrammerEx.Create;
|
||||||
|
fSerializer.DeserializeObject(lJSON, lProgrammerEx, stFields);
|
||||||
|
Assert.AreEqual('child firstname', lProgrammerEx.FirstName);
|
||||||
|
Assert.IsNull(lProgrammerEx.Mentor);
|
||||||
|
finally
|
||||||
|
lProgrammerEx.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeOwnedProperty_WithFieldsUnassigned_JSONExists;
|
||||||
|
const
|
||||||
|
lJSON = '{' +
|
||||||
|
' "fskills": "",' +
|
||||||
|
' "fid": 2,' +
|
||||||
|
' "ffirstname": "child firstname",' +
|
||||||
|
' "flastname": "child lastname",' +
|
||||||
|
' "fdob": null,' +
|
||||||
|
' "fmarried": false,' +
|
||||||
|
' "fmentor": { ' +
|
||||||
|
' "fmentor": null, ' +
|
||||||
|
' "fskills": "superb programmer", ' +
|
||||||
|
' "ffirstname": "mentor firstname", ' +
|
||||||
|
' "flastname": "mentor lasttname", ' +
|
||||||
|
' "fdob": null, ' +
|
||||||
|
' "fmarried": false, ' +
|
||||||
|
' "fid": 2 ' +
|
||||||
|
' }' +
|
||||||
|
' }';
|
||||||
|
var
|
||||||
|
lProgrammerEx: TProgrammerEx;
|
||||||
|
begin
|
||||||
|
lProgrammerEx := TProgrammerEx.Create;
|
||||||
|
try
|
||||||
|
fSerializer.DeserializeObject(lJSON, lProgrammerEx, stFields);
|
||||||
|
Assert.AreEqual('child firstname', lProgrammerEx.FirstName);
|
||||||
|
Assert.IsNotNull(lProgrammerEx.Mentor);
|
||||||
|
Assert.IsNull(lProgrammerEx.Mentor.Mentor);
|
||||||
|
Assert.AreEqual('mentor firstname', lProgrammerEx.Mentor.FirstName);
|
||||||
|
finally
|
||||||
|
lProgrammerEx.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeOwnedProperty_WithPropertyAssigned_JSONExists;
|
||||||
|
const
|
||||||
|
lJSON = '{' +
|
||||||
|
' "skills": "",' +
|
||||||
|
' "id": 2,' +
|
||||||
|
' "firstname": "child firstname",' +
|
||||||
|
' "lastname": "child lastname",' +
|
||||||
|
' "dob": null,' +
|
||||||
|
' "married": false,' +
|
||||||
|
' "mentor": { ' +
|
||||||
|
' "mentor": null, ' +
|
||||||
|
' "skills": "superb programmer", ' +
|
||||||
|
' "firstname": "mentor firstname", ' +
|
||||||
|
' "lastname": "mentor lasttname", ' +
|
||||||
|
' "dob": null, ' +
|
||||||
|
' "married": false, ' +
|
||||||
|
' "id": 2 ' +
|
||||||
|
' }' +
|
||||||
|
' }';
|
||||||
|
var
|
||||||
|
lProgrammerEx: TProgrammerEx;
|
||||||
|
begin
|
||||||
|
lProgrammerEx := TProgrammerEx.Create;
|
||||||
|
try
|
||||||
|
lProgrammerEx.Mentor := TProgrammerEx.Create;
|
||||||
|
fSerializer.DeserializeObject(lJSON, lProgrammerEx);
|
||||||
|
Assert.AreEqual('child firstname', lProgrammerEx.FirstName);
|
||||||
|
Assert.IsNotNull(lProgrammerEx.Mentor);
|
||||||
|
Assert.IsNull(lProgrammerEx.Mentor.Mentor);
|
||||||
|
Assert.AreEqual('mentor firstname', lProgrammerEx.Mentor.FirstName);
|
||||||
|
finally
|
||||||
|
lProgrammerEx.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeOwnedProperty_WithPropertyAssigned_JSONNotExists;
|
||||||
|
const
|
||||||
|
lJSON = '{' +
|
||||||
|
' "skills": "",' +
|
||||||
|
' "id": 2,' +
|
||||||
|
' "firstname": "child firstname",' +
|
||||||
|
' "lastname": "child lastname",' +
|
||||||
|
' "dob": null,' +
|
||||||
|
' "married": false' +
|
||||||
|
' }';
|
||||||
|
var
|
||||||
|
lProgrammerEx: TProgrammerEx;
|
||||||
|
begin
|
||||||
|
lProgrammerEx := TProgrammerEx.Create;
|
||||||
|
try
|
||||||
|
lProgrammerEx.Mentor := TProgrammerEx.Create;
|
||||||
|
lProgrammerEx.Mentor.FirstName := 'existent_value';
|
||||||
|
fSerializer.DeserializeObject(lJSON, lProgrammerEx);
|
||||||
|
Assert.AreEqual('child firstname', lProgrammerEx.FirstName);
|
||||||
|
Assert.IsNotNull(lProgrammerEx.Mentor);
|
||||||
|
Assert.AreEqual('existent_value', lProgrammerEx.Mentor.FirstName);
|
||||||
|
finally
|
||||||
|
lProgrammerEx.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TMVCTestSerializerJsonDataObjects.TestDeserializeOwnedProperty_WithPropertyAssigned_JSONNull;
|
||||||
|
const
|
||||||
|
lJSON = '{' +
|
||||||
|
' "skills": "",' +
|
||||||
|
' "id": 2,' +
|
||||||
|
' "firstname": "child firstname",' +
|
||||||
|
' "lastname": "child lastname",' +
|
||||||
|
' "dob": null,' +
|
||||||
|
' "married": false,' +
|
||||||
|
' "mentor": null ' +
|
||||||
|
' }';
|
||||||
|
var
|
||||||
|
lProgrammerEx: TProgrammerEx;
|
||||||
|
begin
|
||||||
|
lProgrammerEx := TProgrammerEx.Create;
|
||||||
|
try
|
||||||
|
lProgrammerEx.Mentor := TProgrammerEx.Create;
|
||||||
|
fSerializer.DeserializeObject(lJSON, lProgrammerEx);
|
||||||
|
Assert.AreEqual('child firstname', lProgrammerEx.FirstName);
|
||||||
|
Assert.IsNull(lProgrammerEx.Mentor);
|
||||||
|
finally
|
||||||
|
lProgrammerEx.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TMVCTestSerializerJsonDataObjects.TestDoNotSerializeDoNotDeSerialize;
|
procedure TMVCTestSerializerJsonDataObjects.TestDoNotSerializeDoNotDeSerialize;
|
||||||
var
|
var
|
||||||
lObj: TPartialSerializableType;
|
lObj: TPartialSerializableType;
|
||||||
|
@ -308,6 +308,14 @@ type
|
|||||||
procedure PostInject50(const [MVCFromBody] People: TObjectList<TPerson>);
|
procedure PostInject50(const [MVCFromBody] People: TObjectList<TPerson>);
|
||||||
|
|
||||||
|
|
||||||
|
[MVCHTTPMethod([httpPOST])]
|
||||||
|
[MVCPath('/programmerex')]
|
||||||
|
procedure CreateProgrammerEx(const [MVCFromBody] ProgrammerEx: TProgrammerEx);
|
||||||
|
|
||||||
|
[MVCHTTPMethod([httpPOST])]
|
||||||
|
[MVCPath('/programmerex2')]
|
||||||
|
procedure CreateProgrammerEx2(const [MVCFromBody] ProgrammerEx2: TProgrammerEx2);
|
||||||
|
|
||||||
{ templates }
|
{ templates }
|
||||||
[MVCHTTPMethod([httpGET])]
|
[MVCHTTPMethod([httpGET])]
|
||||||
[MVCPath('/website/list')]
|
[MVCPath('/website/list')]
|
||||||
@ -362,6 +370,18 @@ uses
|
|||||||
|
|
||||||
{ TTestServerController }
|
{ TTestServerController }
|
||||||
|
|
||||||
|
procedure TTestServerController.CreateProgrammerEx(
|
||||||
|
const ProgrammerEx: TProgrammerEx);
|
||||||
|
begin
|
||||||
|
Render(ProgrammerEx, False);
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure TTestServerController.CreateProgrammerEx2(
|
||||||
|
const ProgrammerEx2: TProgrammerEx2);
|
||||||
|
begin
|
||||||
|
Render(ProgrammerEx2, False);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TTestServerController.DataSetHandling;
|
procedure TTestServerController.DataSetHandling;
|
||||||
begin
|
begin
|
||||||
case Context.Request.HTTPMethod of
|
case Context.Request.HTTPMethod of
|
||||||
|
Loading…
Reference in New Issue
Block a user