mirror of
https://github.com/danieleteti/delphimvcframework.git
synced 2024-11-15 07:45: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)
|
||||
|
||||
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! `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 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`.
|
||||
|
||||
> 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;
|
||||
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)]
|
||||
TPhilosopher = class(TPerson)
|
||||
private
|
||||
@ -659,6 +681,22 @@ begin
|
||||
fPeople := Value;
|
||||
end;
|
||||
|
||||
{ TProgrammerEx }
|
||||
|
||||
destructor TProgrammerEx.Destroy;
|
||||
begin
|
||||
FMentor.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
{ TProgrammerEx2 }
|
||||
|
||||
destructor TProgrammerEx2.Destroy;
|
||||
begin
|
||||
FMentor.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
Randomize;
|
||||
|
@ -185,6 +185,15 @@ type
|
||||
property MappedValues: TList<string> read FMappedValues;
|
||||
end;
|
||||
|
||||
|
||||
MVCOwnedAttribute = class(TCustomAttribute)
|
||||
private
|
||||
fClassRef: TClass;
|
||||
public
|
||||
constructor Create(const ClassRef: TClass = nil);
|
||||
property ClassRef: TClass read fClassRef;
|
||||
end;
|
||||
|
||||
TMVCSerializerHelper = record
|
||||
private
|
||||
{ private declarations }
|
||||
@ -214,7 +223,7 @@ type
|
||||
class function StringToTypeKind(const AValue: string): TTypeKind; static;
|
||||
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; inline;
|
||||
end;
|
||||
|
||||
TMVCLinksCallback = reference to procedure(const Links: TMVCStringDictionary);
|
||||
@ -1731,6 +1740,14 @@ begin
|
||||
inherited;
|
||||
end;
|
||||
|
||||
{ MVCOwnedAttribute }
|
||||
|
||||
constructor MVCOwnedAttribute.Create(const ClassRef: TClass);
|
||||
begin
|
||||
inherited Create;
|
||||
fClassRef := ClassRef;
|
||||
end;
|
||||
|
||||
initialization
|
||||
|
||||
gLocalTimeStampAsUTC := False;
|
||||
|
@ -92,7 +92,8 @@ type
|
||||
function TryNullableToJSON(const AValue: TValue; const AJsonObject: TJDOJsonObject; const AName: string): Boolean;
|
||||
procedure JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
||||
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 ACustomAttributes: TArray<TCustomAttribute>);
|
||||
procedure JsonArrayToList(const AJsonArray: TJDOJsonArray; const AList: IMVCList; const AClazz: TClass;
|
||||
@ -1098,14 +1099,18 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCJsonDataObjectsSerializer.JsonDataValueToAttribute(const AJsonObject: TJDOJsonObject; const AName: string;
|
||||
var AValue: TValue; const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
|
||||
const ACustomAttributes: TArray<TCustomAttribute>);
|
||||
procedure TMVCJsonDataObjectsSerializer.JsonDataValueToAttribute(
|
||||
const AObject: TObject;
|
||||
const ARttiMember: TRttiMember;
|
||||
const AJsonObject: TJDOJsonObject;
|
||||
const AName: string; var AValue: TValue; const AType: TMVCSerializationType;
|
||||
const AIgnored: TMVCIgnoredList; const ACustomAttributes: TArray<TCustomAttribute>);
|
||||
var
|
||||
ChildObject: TObject;
|
||||
ChildList: IMVCList;
|
||||
ChildListOfAtt: MVCListOfAttribute;
|
||||
LEnumAsAttr: MVCEnumSerializationAttribute;
|
||||
lOwnedAttribute: MVCOwnedAttribute;
|
||||
LEnumMappedValues: TList<string>;
|
||||
LEnumSerType: TMVCEnumSerializationType;
|
||||
LClazz: TClass;
|
||||
@ -1113,17 +1118,85 @@ var
|
||||
lOutInteger: Integer;
|
||||
lOutInteger64: Int64;
|
||||
lTypeInfo: PTypeInfo;
|
||||
lJSONExists: Boolean;
|
||||
lJSONIsNull: Boolean;
|
||||
lChildObjectAssigned: Boolean;
|
||||
begin
|
||||
ChildObject := nil;
|
||||
lTypeInfo := AValue.TypeInfo;
|
||||
if AValue.Kind in [tkClass, tkInterface] then
|
||||
begin
|
||||
ChildObject := nil;
|
||||
if not AValue.IsEmpty and (AValue.Kind = tkInterface) then
|
||||
ChildObject := TObject(AValue.AsInterface)
|
||||
else if AValue.Kind = tkClass then
|
||||
ChildObject := AValue.AsObject;
|
||||
if not AValue.IsEmpty then
|
||||
begin
|
||||
if AValue.Kind = tkInterface then
|
||||
ChildObject := TObject(AValue.AsInterface)
|
||||
else
|
||||
ChildObject := AValue.AsObject;
|
||||
end;
|
||||
|
||||
if Assigned(ChildObject) then
|
||||
lTypeInfo := ChildObject.ClassInfo;
|
||||
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;
|
||||
case AType of
|
||||
stUnknown, stDefault, stProperties:
|
||||
TRttiProperty(ARttiMember).SetValue(AObject, ChildObject);
|
||||
stFields:
|
||||
TRttiField(ARttiMember).SetValue(AObject, ChildObject);
|
||||
end;
|
||||
end; //end cases
|
||||
end;
|
||||
end;
|
||||
|
||||
if GetTypeSerializers.ContainsKey(lTypeInfo) then
|
||||
@ -1325,13 +1398,13 @@ begin
|
||||
case AValue.Kind of
|
||||
tkInterface:
|
||||
begin
|
||||
ChildObject := TObject(AValue.AsInterface);
|
||||
//ChildObject := TObject(AValue.AsInterface);
|
||||
JsonObjectToObject(AJsonObject.O[AName], ChildObject, GetSerializationType(ChildObject, AType),
|
||||
AIgnored);
|
||||
end;
|
||||
tkClass:
|
||||
begin
|
||||
ChildObject := AValue.AsObject;
|
||||
//ChildObject := AValue.AsObject;
|
||||
JsonObjectToObject(AJsonObject.O[AName], ChildObject, GetSerializationType(ChildObject, AType),
|
||||
AIgnored);
|
||||
end;
|
||||
@ -1511,8 +1584,9 @@ begin
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMVCJsonDataObjectsSerializer.JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
||||
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
||||
procedure TMVCJsonDataObjectsSerializer.JsonObjectToObject(const AJsonObject: TJDOJsonObject;
|
||||
const AObject: TObject; const AType: TMVCSerializationType;
|
||||
const AIgnoredAttributes: TMVCIgnoredList);
|
||||
var
|
||||
lObjType: TRttiType;
|
||||
lProp: TRttiProperty;
|
||||
@ -1558,7 +1632,9 @@ begin
|
||||
begin
|
||||
lAttributeValue := lProp.GetValue(AObject);
|
||||
lKeyName := TMVCSerializerHelper.GetKeyName(lProp, lObjType);
|
||||
JsonDataValueToAttribute(AJsonObject, lKeyName, lAttributeValue, AType, AIgnoredAttributes,
|
||||
JsonDataValueToAttribute(
|
||||
AObject, lProp,
|
||||
AJsonObject, lKeyName, lAttributeValue, AType, AIgnoredAttributes,
|
||||
lProp.GetAttributes);
|
||||
if (not lAttributeValue.IsEmpty) and (not lAttributeValue.IsObject) and lProp.IsWritable then
|
||||
begin
|
||||
@ -1592,9 +1668,12 @@ begin
|
||||
begin
|
||||
lAttributeValue := lFld.GetValue(AObject);
|
||||
lKeyName := TMVCSerializerHelper.GetKeyName(lFld, lObjType);
|
||||
JsonDataValueToAttribute(AJsonObject, lKeyName, lAttributeValue, AType, AIgnoredAttributes,
|
||||
lFld.GetAttributes);
|
||||
if not lAttributeValue.IsEmpty then
|
||||
JsonDataValueToAttribute(
|
||||
AObject, lFld,
|
||||
AJsonObject, lKeyName,
|
||||
lAttributeValue, AType,
|
||||
AIgnoredAttributes, lFld.GetAttributes);
|
||||
if (not lAttributeValue.IsEmpty) and (not lAttributeValue.IsObject) then
|
||||
lFld.SetValue(AObject, lAttributeValue);
|
||||
end;
|
||||
except
|
||||
|
@ -219,6 +219,7 @@
|
||||
</DCCReference>
|
||||
<DCCReference Include="..\..\..\sources\MVCFramework.Commons.pas"/>
|
||||
<DCCReference Include="..\..\..\sources\MVCFramework.Serializer.JsonDataObjects.CustomTypes.pas"/>
|
||||
<DCCReference Include="..\..\..\sources\MVCFramework.SQLGenerators.Firebird.pas"/>
|
||||
<BuildConfiguration Include="Base">
|
||||
<Key>Base</Key>
|
||||
</BuildConfiguration>
|
||||
|
@ -58,7 +58,6 @@ type
|
||||
|
||||
{ serialize declarations }
|
||||
[Test]
|
||||
// [Category('this')]
|
||||
procedure TestSerializeAllTypes;
|
||||
[Test]
|
||||
procedure TestSerializeDateTimeProperty;
|
||||
@ -73,7 +72,6 @@ type
|
||||
[Test]
|
||||
procedure TestSerializeEntityUpperCaseNames;
|
||||
[Test]
|
||||
// [Category('this')]
|
||||
procedure TestSerializeEntityWithArray;
|
||||
[Test]
|
||||
procedure TestSerializeEntityLowerCaseNames;
|
||||
@ -139,6 +137,38 @@ type
|
||||
[Test]
|
||||
[Category('serializers')]
|
||||
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;
|
||||
|
||||
TMVCEntityCustomSerializerJsonDataObjects = class(TInterfacedObject, IMVCTypeSerializer)
|
||||
@ -578,6 +608,244 @@ begin
|
||||
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;
|
||||
var
|
||||
lObj: TPartialSerializableType;
|
||||
|
@ -308,6 +308,14 @@ type
|
||||
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 }
|
||||
[MVCHTTPMethod([httpGET])]
|
||||
[MVCPath('/website/list')]
|
||||
@ -362,6 +370,18 @@ uses
|
||||
|
||||
{ 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;
|
||||
begin
|
||||
case Context.Request.HTTPMethod of
|
||||
|
Loading…
Reference in New Issue
Block a user