2017-03-01 21:40:57 +01:00
|
|
|
|
// ***************************************************************************
|
|
|
|
|
//
|
|
|
|
|
// Delphi MVC Framework
|
|
|
|
|
//
|
2020-01-06 16:49:18 +01:00
|
|
|
|
// Copyright (c) 2010-2020 Daniele Teti and the DMVCFramework Team
|
2017-03-01 21:40:57 +01:00
|
|
|
|
//
|
|
|
|
|
// 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 MVCFramework.Serializer.JsonDataObjects;
|
|
|
|
|
|
2017-03-23 18:51:25 +01:00
|
|
|
|
{$I dmvcframework.inc}
|
|
|
|
|
|
2017-03-01 21:40:57 +01:00
|
|
|
|
interface
|
|
|
|
|
|
|
|
|
|
uses
|
|
|
|
|
System.Classes,
|
|
|
|
|
System.Rtti,
|
|
|
|
|
System.TypInfo,
|
|
|
|
|
System.Variants,
|
|
|
|
|
System.Generics.Collections,
|
2017-03-29 14:49:35 +02:00
|
|
|
|
Data.SqlTimSt,
|
|
|
|
|
Data.FmtBcd,
|
2017-03-01 21:40:57 +01:00
|
|
|
|
Data.DB,
|
2019-03-10 16:29:18 +01:00
|
|
|
|
MVCFramework.Commons,
|
2017-03-01 21:40:57 +01:00
|
|
|
|
MVCFramework.Serializer.Intf,
|
2017-03-28 14:52:13 +02:00
|
|
|
|
MVCFramework.Serializer.Abstract,
|
2017-03-01 21:40:57 +01:00
|
|
|
|
MVCFramework.Serializer.Commons,
|
|
|
|
|
MVCFramework.DuckTyping,
|
2018-11-24 16:56:21 +01:00
|
|
|
|
System.JSON,
|
2020-03-12 21:19:30 +01:00
|
|
|
|
JsonDataObjects,
|
|
|
|
|
System.SysUtils;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
type
|
2019-04-16 23:12:19 +02:00
|
|
|
|
|
|
|
|
|
TMVCDataSetField = record
|
2019-04-17 16:47:07 +02:00
|
|
|
|
FieldName: string;
|
2019-04-16 23:12:19 +02:00
|
|
|
|
DataType: TFieldType;
|
|
|
|
|
I: Integer;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
TMVCDataSetFieldSerializationAction = reference to procedure(const AField: TField; const AJsonObject: TJsonObject;
|
|
|
|
|
var Handled: Boolean);
|
2019-09-25 09:14:09 +02:00
|
|
|
|
|
2019-04-16 23:12:19 +02:00
|
|
|
|
TMVCDataSetFields = TList<TMVCDataSetField>;
|
|
|
|
|
|
2019-11-06 15:08:29 +01:00
|
|
|
|
TJSONObjectHelper = class helper for TJsonObject
|
|
|
|
|
public
|
|
|
|
|
procedure LoadFromString(const Value: String; Encoding: TEncoding = nil; Utf8WithoutBOM: Boolean = True);
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-02 12:57:40 +01:00
|
|
|
|
TMVCJsonDataObjectsSerializer = class(TMVCAbstractSerializer, IMVCSerializer)
|
2019-03-08 09:33:41 +01:00
|
|
|
|
private
|
|
|
|
|
fStringDictionarySerializer: IMVCTypeSerializer;
|
2019-09-30 00:05:46 +02:00
|
|
|
|
public
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function GetDataSetFields(const ADataSet: TDataSet; const AIgnoredFields: TMVCIgnoredList = [];
|
2019-04-16 23:12:19 +02:00
|
|
|
|
const ANameCase: TMVCNameCase = ncAsIs): TMVCDataSetFields;
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure ObjectToJsonObject(const AObject: TObject; const AJsonObject: TJDOJsonObject;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure InternalObjectToJsonObject(const AObject: TObject; const AJsonObject: TJDOJsonObject;
|
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
|
2019-05-09 20:53:52 +02:00
|
|
|
|
const ASerializationAction: TMVCSerializationAction; const Links: IMVCLinks;
|
2019-03-08 09:33:41 +01:00
|
|
|
|
const Serializer: IMVCTypeSerializer);
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure ListToJsonArray(const AList: IMVCList; const AJsonArray: TJDOJsonArray;
|
2019-03-08 09:33:41 +01:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
|
|
|
|
|
const ASerializationAction: TMVCSerializationAction = nil);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure AttributeToJsonDataValue(const AJsonObject: TJDOJsonObject; const AName: string; const AValue: TValue;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
|
|
|
|
|
const ACustomAttributes: TArray<TCustomAttribute>);
|
2020-02-03 10:51:40 +01:00
|
|
|
|
function TryNullableToJSON(const AValue: TValue; const AJsonObject: TJDOJsonObject; const AName: String): Boolean;
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure JsonDataValueToAttribute(const AJsonObject: TJDOJsonObject; const AName: string; var AValue: TValue;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
|
|
|
|
|
const ACustomAttributes: TArray<TCustomAttribute>);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure JsonArrayToList(const AJsonArray: TJDOJsonArray; const AList: IMVCList; const AClazz: TClass;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure DataSetToJsonObject(const ADataSet: TDataSet; const AJsonObject: TJDOJsonObject;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const ANameCase: TMVCNameCase; const AIgnoredFields: TMVCIgnoredList; const ADataSetFields: TMVCDataSetFields;
|
|
|
|
|
const ASerializationCallback: TMVCDataSetFieldSerializationAction = nil);
|
|
|
|
|
procedure DataSetRowToJsonArrayOfValues(const ADataSet: TDataSet; const AJsonArray: TJDOJsonArray;
|
|
|
|
|
const AIgnoredFields: TMVCIgnoredList; const ADataSetFields: TMVCDataSetFields);
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure DataSetToJsonArray(const ADataSet: TDataSet; const AJsonArray: TJDOJsonArray;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const ANameCase: TMVCNameCase; const AIgnoredFields: TMVCIgnoredList;
|
|
|
|
|
const ASerializationCallback: TMVCDataSetFieldSerializationAction = nil);
|
|
|
|
|
procedure DataSetToJsonArrayOfValues(const ADataSet: TDataSet; const AJsonArray: TJDOJsonArray;
|
|
|
|
|
const AIgnoredFields: TMVCIgnoredList);
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure JsonObjectToDataSet(const AJsonObject: TJDOJsonObject; const ADataSet: TDataSet;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure JsonArrayToDataSet(const AJsonArray: TJDOJsonArray; const ADataSet: TDataSet;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function JsonArrayToArray(const AJsonArray: TJDOJsonArray): TValue;
|
2017-09-07 00:10:21 +02:00
|
|
|
|
{ IMVCSerializer }
|
2018-07-16 12:34:07 +02:00
|
|
|
|
function SerializeObject(const AObject: TObject; const AType: TMVCSerializationType = stDefault;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList = []; const ASerializationAction: TMVCSerializationAction = nil)
|
|
|
|
|
: string; overload;
|
2019-09-18 01:14:54 +02:00
|
|
|
|
|
|
|
|
|
function SerializeObject(const AObject: IInterface; const AType: TMVCSerializationType = stDefault;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList = []; const ASerializationAction: TMVCSerializationAction = nil)
|
|
|
|
|
: string; overload;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
|
2018-12-12 11:00:41 +01:00
|
|
|
|
function SerializeObjectToJSON(const AObject: TObject; const AType: TMVCSerializationType;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): TJDOJsonObject;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function SerializeCollection(const AList: TObject; const AType: TMVCSerializationType = stDefault;
|
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList = []; const ASerializationAction: TMVCSerializationAction = nil)
|
|
|
|
|
: string; overload;
|
2019-09-18 01:14:54 +02:00
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function SerializeCollection(const AList: IInterface; const AType: TMVCSerializationType = stDefault;
|
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList = []; const ASerializationAction: TMVCSerializationAction = nil)
|
|
|
|
|
: string; overload;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function SerializeDataSet(const ADataSet: TDataSet; const AIgnoredFields: TMVCIgnoredList = [];
|
|
|
|
|
const ANameCase: TMVCNameCase = ncAsIs; const ASerializationAction: TMVCDatasetSerializationAction = nil): string;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function SerializeDataSetRecord(const ADataSet: TDataSet; const AIgnoredFields: TMVCIgnoredList = [];
|
|
|
|
|
const ANameCase: TMVCNameCase = ncAsIs; const ASerializationAction: TMVCDatasetSerializationAction = nil): string;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
|
|
|
|
|
procedure DeserializeObject(const ASerializedObject: string; const AObject: TObject;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = []); overload;
|
2019-09-18 01:14:54 +02:00
|
|
|
|
|
|
|
|
|
procedure DeserializeObject(const ASerializedObject: string; const AObject: IInterface;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = []); overload;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure DeserializeCollection(const ASerializedList: string; const AList: TObject; const AClazz: TClass;
|
|
|
|
|
const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = []); overload;
|
2019-09-18 01:14:54 +02:00
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure DeserializeCollection(const ASerializedList: string; const AList: IInterface; const AClazz: TClass;
|
|
|
|
|
const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = []); overload;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
|
|
|
|
|
procedure DeserializeDataSet(const ASerializedDataSet: string; const ADataSet: TDataSet;
|
|
|
|
|
const AIgnoredFields: TMVCIgnoredList = []; const ANameCase: TMVCNameCase = ncAsIs);
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure DeserializeDataSetRecord(const ASerializedDataSetRecord: string; const ADataSet: TDataSet;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AIgnoredFields: TMVCIgnoredList = []; const ANameCase: TMVCNameCase = ncAsIs);
|
2019-01-08 12:48:27 +01:00
|
|
|
|
class function ParseObject(const AString: string): TJDOJsonObject;
|
|
|
|
|
class function ParseArray(const AString: string): TJDOJsonArray;
|
2018-10-23 16:18:34 +02:00
|
|
|
|
class function Parse<T: TJsonBaseObject>(const AString: string): T;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
public
|
2017-03-02 12:57:40 +01:00
|
|
|
|
procedure AfterConstruction; override;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TValueToJsonElement(const Value: TValue; const JSON: TJDOJsonObject; const KeyName: string);
|
2019-09-30 00:05:46 +02:00
|
|
|
|
function StrToJSONObject(const AValue: string): TJDOJsonObject;
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2018-12-12 14:48:35 +01:00
|
|
|
|
|
2017-03-01 21:40:57 +01:00
|
|
|
|
implementation
|
|
|
|
|
|
|
|
|
|
uses
|
2018-10-14 18:23:20 +02:00
|
|
|
|
MVCFramework.Serializer.JsonDataObjects.CustomTypes,
|
2020-03-12 21:19:30 +01:00
|
|
|
|
MVCFramework.Logger,
|
|
|
|
|
MVCFramework.DataSet.Utils,
|
2020-02-03 10:51:40 +01:00
|
|
|
|
MVCFramework.Nullables;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
2019-05-09 20:53:52 +02:00
|
|
|
|
type
|
|
|
|
|
TJDOLinks = class(TMVCLinks)
|
|
|
|
|
public
|
|
|
|
|
procedure FillJSONArray(const AJsonArray: TJsonArray);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ TMVCJsonDataObjectsSerializer }
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
2017-03-02 12:57:40 +01:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.AfterConstruction;
|
2019-03-05 20:55:37 +01:00
|
|
|
|
var
|
|
|
|
|
lStreamSerializer: IMVCTypeSerializer;
|
2019-09-30 00:05:46 +02:00
|
|
|
|
lDataSetHolderSerializer: TMVCDataSetHolderSerializer;
|
2017-03-02 12:57:40 +01:00
|
|
|
|
begin
|
|
|
|
|
inherited AfterConstruction;
|
2019-09-30 00:05:46 +02:00
|
|
|
|
lDataSetHolderSerializer := TMVCDataSetHolderSerializer.Create;
|
|
|
|
|
GetTypeSerializers.Add(TypeInfo(TDataSetHolder), lDataSetHolderSerializer);
|
2019-03-05 20:55:37 +01:00
|
|
|
|
lStreamSerializer := TMVCStreamSerializerJsonDataObject.Create;
|
|
|
|
|
GetTypeSerializers.Add(TypeInfo(TStream), lStreamSerializer);
|
|
|
|
|
GetTypeSerializers.Add(TypeInfo(TStringStream), lStreamSerializer);
|
|
|
|
|
GetTypeSerializers.Add(TypeInfo(TFileStream), lStreamSerializer);
|
|
|
|
|
GetTypeSerializers.Add(TypeInfo(TMemoryStream), lStreamSerializer);
|
2019-03-08 09:33:41 +01:00
|
|
|
|
fStringDictionarySerializer := TMVCStringDictionarySerializer.Create;
|
2018-10-31 01:07:23 +01:00
|
|
|
|
GetTypeSerializers.Add(TypeInfo(TMVCStringDictionary), TMVCStringDictionarySerializer.Create);
|
2019-06-26 19:31:53 +02:00
|
|
|
|
GetTypeSerializers.Add(TypeInfo(TGUID), TMVCGUIDSerializer.Create);
|
2017-03-02 12:57:40 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.AttributeToJsonDataValue(const AJsonObject: TJDOJsonObject; const AName: string;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
const AValue: TValue; const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
const ACustomAttributes: TArray<TCustomAttribute>);
|
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
ChildJsonObject: TJDOJsonObject;
|
|
|
|
|
ChildJsonArray: TJDOJsonArray;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
ChildValue: TValue;
|
|
|
|
|
ChildObject, Obj: TObject;
|
|
|
|
|
ChildList: IMVCList;
|
|
|
|
|
ValueTypeAtt: MVCValueAsTypeAttribute;
|
|
|
|
|
CastValue, CastedValue: TValue;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
I: Integer;
|
2020-03-12 20:37:48 +01:00
|
|
|
|
LEnumAsAttr: MVCEnumSerializationAttribute;
|
2019-08-12 21:48:33 +02:00
|
|
|
|
LEnumSerType: TMVCEnumSerializationType;
|
2020-03-12 18:24:20 +01:00
|
|
|
|
LEnumMappedValues: TList<string>;
|
2019-08-12 21:48:33 +02:00
|
|
|
|
LEnumName: string;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2019-10-10 20:16:20 +02:00
|
|
|
|
if SameText(AName, 'RefCount') then
|
|
|
|
|
begin
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-01 21:40:57 +01:00
|
|
|
|
if AValue.IsEmpty then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject[AName] := Null;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-02 12:57:40 +01:00
|
|
|
|
if GetTypeSerializers.ContainsKey(AValue.TypeInfo) then
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
GetTypeSerializers.Items[AValue.TypeInfo].SerializeAttribute(AValue, AName, AJsonObject, ACustomAttributes);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
case AValue.Kind of
|
|
|
|
|
tkInteger:
|
|
|
|
|
AJsonObject.I[AName] := AValue.AsInteger;
|
|
|
|
|
|
|
|
|
|
tkInt64:
|
|
|
|
|
AJsonObject.L[AName] := AValue.AsInt64;
|
|
|
|
|
|
|
|
|
|
tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
|
|
|
|
|
AJsonObject.S[AName] := AValue.AsString;
|
|
|
|
|
|
|
|
|
|
tkFloat:
|
|
|
|
|
begin
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(TDate)) then
|
|
|
|
|
begin
|
|
|
|
|
if (AValue.AsExtended = 0) then
|
|
|
|
|
AJsonObject[AName] := Null
|
|
|
|
|
else
|
|
|
|
|
AJsonObject.S[AName] := DateToISODate(AValue.AsExtended);
|
|
|
|
|
end
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if (AValue.TypeInfo = System.TypeInfo(TDateTime)) then
|
2019-05-16 00:16:55 +02:00
|
|
|
|
begin
|
|
|
|
|
if (AValue.AsExtended = 0) then
|
|
|
|
|
AJsonObject[AName] := Null
|
2019-05-09 20:53:52 +02:00
|
|
|
|
else
|
2019-05-16 00:16:55 +02:00
|
|
|
|
AJsonObject.S[AName] := DateTimeToISOTimeStamp(AValue.AsExtended);
|
|
|
|
|
end
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if (AValue.TypeInfo = System.TypeInfo(TTime)) then
|
2019-05-16 00:16:55 +02:00
|
|
|
|
begin
|
|
|
|
|
if (AValue.AsExtended = 0) then
|
|
|
|
|
AJsonObject[AName] := Null
|
|
|
|
|
else
|
|
|
|
|
AJsonObject.S[AName] := TimeToISOTime(AValue.AsExtended);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
AJsonObject.F[AName] := AValue.AsExtended;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
tkVariant:
|
|
|
|
|
AJsonObject[AName] := AValue.AsVariant;
|
|
|
|
|
|
|
|
|
|
tkEnumeration:
|
|
|
|
|
begin
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(Boolean)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsBoolean then
|
|
|
|
|
AJsonObject.B[AName] := True
|
|
|
|
|
else
|
|
|
|
|
AJsonObject.B[AName] := False
|
|
|
|
|
end
|
|
|
|
|
else
|
2019-08-12 21:48:33 +02:00
|
|
|
|
begin
|
|
|
|
|
LEnumSerType := estEnumName;
|
2020-03-12 18:24:20 +01:00
|
|
|
|
LEnumMappedValues := nil;
|
2020-03-12 20:37:48 +01:00
|
|
|
|
if TMVCSerializerHelper.AttributeExists<MVCEnumSerializationAttribute>(ACustomAttributes, LEnumAsAttr)
|
2019-10-24 15:34:40 +02:00
|
|
|
|
then
|
2019-08-12 21:48:33 +02:00
|
|
|
|
begin
|
2020-03-12 18:24:20 +01:00
|
|
|
|
LEnumSerType := LEnumAsAttr.SerializationType;
|
|
|
|
|
LEnumMappedValues := LEnumAsAttr.MappedValues;
|
2019-08-12 21:48:33 +02:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
case LEnumSerType of
|
|
|
|
|
estEnumName:
|
|
|
|
|
begin
|
|
|
|
|
LEnumName := GetEnumName(AValue.TypeInfo, AValue.AsOrdinal);
|
|
|
|
|
|
|
|
|
|
AJsonObject.S[AName] := LEnumName;
|
|
|
|
|
end;
|
|
|
|
|
estEnumOrd:
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.I[AName] := AValue.AsOrdinal;
|
|
|
|
|
end;
|
2020-03-12 18:24:20 +01:00
|
|
|
|
estEnumMappedValues:
|
|
|
|
|
begin
|
|
|
|
|
if (LEnumMappedValues.Count - 1) < AValue.AsOrdinal then
|
|
|
|
|
raise EMVCException.Create('Enumerator value is not mapped in MappedValues');
|
|
|
|
|
|
|
|
|
|
AJsonObject.S[AName] := LEnumMappedValues[AValue.AsOrdinal];
|
|
|
|
|
end;
|
2019-08-12 21:48:33 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2019-09-18 13:30:50 +02:00
|
|
|
|
tkClass, tkInterface:
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2019-09-18 13:30:50 +02:00
|
|
|
|
ChildObject := nil;
|
|
|
|
|
if not AValue.IsEmpty and (AValue.Kind = tkInterface) then
|
|
|
|
|
ChildObject := TObject(AValue.AsInterface)
|
|
|
|
|
else if AValue.Kind = tkClass then
|
|
|
|
|
ChildObject := AValue.AsObject;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
|
2017-03-01 21:40:57 +01:00
|
|
|
|
if Assigned(ChildObject) then
|
|
|
|
|
begin
|
2018-07-16 12:34:07 +02:00
|
|
|
|
if ChildObject is TDataSet then
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
|
|
|
|
ChildJsonArray := AJsonObject.A[AName];
|
2018-07-16 12:34:07 +02:00
|
|
|
|
DataSetToJsonArray(TDataSet(ChildObject), ChildJsonArray, TMVCNameCase.ncLowerCase, []);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end
|
2019-11-05 14:40:39 +01:00
|
|
|
|
else if ChildObject is TJsonObject then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.O[AName] := TJsonObject(ChildObject).Clone as TJsonObject;
|
|
|
|
|
end
|
2017-03-01 21:40:57 +01:00
|
|
|
|
else
|
|
|
|
|
begin
|
2018-07-16 12:34:07 +02:00
|
|
|
|
ChildList := TDuckTypedList.Wrap(ChildObject);
|
|
|
|
|
if Assigned(ChildList) then
|
|
|
|
|
begin
|
|
|
|
|
ChildJsonArray := AJsonObject.A[AName];
|
|
|
|
|
for Obj in ChildList do
|
2019-03-08 09:33:41 +01:00
|
|
|
|
begin
|
2018-07-16 12:34:07 +02:00
|
|
|
|
if Assigned(Obj) then
|
2019-03-08 09:33:41 +01:00
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
ObjectToJsonObject(Obj, ChildJsonArray.AddObject, GetSerializationType(Obj, AType), AIgnored);
|
2019-03-08 09:33:41 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
ChildJsonObject := AJsonObject.O[AName];
|
2019-10-24 15:34:40 +02:00
|
|
|
|
ObjectToJsonObject(ChildObject, ChildJsonObject, GetSerializationType(ChildObject, AType), AIgnored);
|
2018-07-16 12:34:07 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
if TMVCSerializerHelper.AttributeExists<MVCSerializeAsStringAttribute>(ACustomAttributes) then
|
2017-03-01 21:40:57 +01:00
|
|
|
|
AJsonObject.S[AName] := EmptyStr
|
|
|
|
|
else
|
|
|
|
|
AJsonObject[AName] := Null;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
tkRecord:
|
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
if String(AValue.TypeInfo.Name).StartsWith('Nullable') then
|
|
|
|
|
begin
|
|
|
|
|
if TryNullableToJSON(AValue, AJsonObject, AName) then
|
|
|
|
|
begin
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-01 21:40:57 +01:00
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(TTimeStamp)) then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.F[AName] := TimeStampToMsecs(AValue.AsType<TTimeStamp>);
|
|
|
|
|
end
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if (AValue.TypeInfo = System.TypeInfo(TValue)) then
|
2019-05-16 00:16:55 +02:00
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
if TMVCSerializerHelper.AttributeExists<MVCValueAsTypeAttribute>(ACustomAttributes, ValueTypeAtt) then
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2019-05-16 00:16:55 +02:00
|
|
|
|
CastValue := AValue.AsType<TValue>;
|
|
|
|
|
if CastValue.TryCast(ValueTypeAtt.ValueTypeInfo, CastedValue) then
|
|
|
|
|
AttributeToJsonDataValue(AJsonObject, AName, CastedValue, stDefault, [], [])
|
2017-03-01 21:40:57 +01:00
|
|
|
|
else
|
2019-05-16 00:16:55 +02:00
|
|
|
|
raise EMVCSerializationException.CreateFmt
|
2019-07-07 17:25:11 +02:00
|
|
|
|
('Cannot serialize property or field "%s" of TypeKind tkRecord (TValue with MVCValueAsTypeAttribute).',
|
2019-05-16 00:16:55 +02:00
|
|
|
|
[AName]);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end
|
|
|
|
|
else
|
2019-05-16 00:16:55 +02:00
|
|
|
|
begin
|
|
|
|
|
ChildValue := AValue.AsType<TValue>;
|
|
|
|
|
ChildJsonObject := AJsonObject.O[AName];
|
2019-10-24 15:34:40 +02:00
|
|
|
|
ChildJsonObject.S['type'] := TMVCSerializerHelper.GetTypeKindAsString(ChildValue.TypeInfo.Kind);
|
2019-05-16 00:16:55 +02:00
|
|
|
|
AttributeToJsonDataValue(ChildJsonObject, 'value', ChildValue, stDefault, [], []);
|
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
raise EMVCSerializationException.CreateFmt
|
2019-07-07 17:25:11 +02:00
|
|
|
|
('Cannot serialize property or field "%s" of TypeKind tkRecord.', [AName]);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
tkSet:
|
2019-07-07 17:25:11 +02:00
|
|
|
|
raise EMVCSerializationException.CreateFmt('Cannot serialize property or field "%s" of TypeKind tkSet.', [AName]);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
2017-07-16 19:36:44 +02:00
|
|
|
|
tkArray, tkDynArray:
|
|
|
|
|
begin
|
2019-09-18 13:30:50 +02:00
|
|
|
|
if AValue.GetArrayLength > 0 then
|
2020-03-12 21:19:30 +01:00
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
for I := 0 to AValue.GetArrayLength - 1 do
|
2020-03-12 21:19:30 +01:00
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
case AValue.GetArrayElement(I).Kind of
|
2019-05-17 16:15:18 +02:00
|
|
|
|
tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
|
2019-10-24 15:34:40 +02:00
|
|
|
|
AJsonObject.A[AName].Add(AValue.GetArrayElement(I).AsString);
|
2019-05-17 16:15:18 +02:00
|
|
|
|
tkInteger:
|
2019-10-24 15:34:40 +02:00
|
|
|
|
AJsonObject.A[AName].Add(AValue.GetArrayElement(I).AsInteger);
|
2019-05-17 16:15:18 +02:00
|
|
|
|
tkInt64:
|
2019-10-24 15:34:40 +02:00
|
|
|
|
AJsonObject.A[AName].Add(AValue.GetArrayElement(I).AsInt64);
|
2019-11-03 16:16:35 +01:00
|
|
|
|
tkFloat:
|
|
|
|
|
AJsonObject.A[AName].Add(AValue.GetArrayElement(I).AsExtended);
|
2019-05-17 16:15:18 +02:00
|
|
|
|
else
|
|
|
|
|
raise EMVCSerializationException.CreateFmt
|
2019-07-07 17:25:11 +02:00
|
|
|
|
('Cannot serialize property or field "%s" of TypeKind tkArray or tkDynArray.', [AName]);
|
2019-05-17 16:15:18 +02:00
|
|
|
|
end;
|
2020-03-12 21:19:30 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
2017-07-16 19:36:44 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
tkUnknown:
|
2019-03-10 16:29:18 +01:00
|
|
|
|
raise EMVCSerializationException.CreateFmt
|
2019-07-07 17:25:11 +02:00
|
|
|
|
('Cannot serialize property or field "%s" of TypeKind tkUnknown.', [AName]);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DataSetRowToJsonArrayOfValues(const ADataSet: TDataSet;
|
|
|
|
|
const AJsonArray: TJDOJsonArray; const AIgnoredFields: TMVCIgnoredList; const ADataSetFields: TMVCDataSetFields);
|
|
|
|
|
var
|
|
|
|
|
lMS: TMemoryStream;
|
|
|
|
|
lSS: TStringStream;
|
|
|
|
|
lNestedDataSet: TDataSet;
|
|
|
|
|
lChildJsonArray: TJDOJsonArray;
|
|
|
|
|
lField: TMVCDataSetField;
|
|
|
|
|
lDataSetFieldsDetail: TMVCDataSetFields;
|
|
|
|
|
begin
|
|
|
|
|
Assert(Assigned(ADataSetFields));
|
|
|
|
|
for lField in ADataSetFields do
|
|
|
|
|
begin
|
|
|
|
|
begin
|
|
|
|
|
if ADataSet.Fields[lField.I].IsNull then
|
|
|
|
|
begin
|
2019-11-06 15:08:29 +01:00
|
|
|
|
AJsonArray.Add(TJsonObject(nil));
|
2019-10-24 15:34:40 +02:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
case lField.DataType of
|
|
|
|
|
ftBoolean:
|
|
|
|
|
AJsonArray.Add(ADataSet.Fields[lField.I].AsBoolean);
|
|
|
|
|
|
|
|
|
|
ftInteger, ftSmallint, ftShortint, ftByte:
|
|
|
|
|
AJsonArray.Add(ADataSet.Fields[lField.I].AsInteger);
|
|
|
|
|
|
|
|
|
|
ftLargeint, ftAutoInc, ftLongword:
|
|
|
|
|
AJsonArray.Add(ADataSet.Fields[lField.I].AsLargeInt);
|
|
|
|
|
{$IFDEF TOKYOORBETTER}
|
|
|
|
|
ftGuid:
|
|
|
|
|
AJsonArray.Add(GUIDToString(ADataSet.Fields[lField.I].AsGuid));
|
|
|
|
|
{$ENDIF}
|
|
|
|
|
ftSingle, ftFloat:
|
|
|
|
|
AJsonArray.Add(ADataSet.Fields[lField.I].AsFloat);
|
|
|
|
|
|
|
|
|
|
ftString, ftMemo:
|
|
|
|
|
AJsonArray.Add(ADataSet.Fields[lField.I].AsString);
|
|
|
|
|
|
|
|
|
|
ftWideString, ftWideMemo:
|
|
|
|
|
AJsonArray.Add(ADataSet.Fields[lField.I].AsWideString);
|
|
|
|
|
|
|
|
|
|
ftDate:
|
|
|
|
|
AJsonArray.Add(DateToISODate(ADataSet.Fields[lField.I].AsDateTime));
|
|
|
|
|
|
|
|
|
|
ftDateTime:
|
|
|
|
|
AJsonArray.Add(DateTimeToISOTimeStamp(ADataSet.Fields[lField.I].AsDateTime));
|
|
|
|
|
|
|
|
|
|
ftTime:
|
|
|
|
|
AJsonArray.Add(SQLTimeStampToStr('hh:nn:ss', ADataSet.Fields[lField.I].AsSQLTimeStamp));
|
|
|
|
|
|
|
|
|
|
ftTimeStamp:
|
|
|
|
|
AJsonArray.Add(DateTimeToISOTimeStamp(SQLTimeStampToDateTime(ADataSet.Fields[lField.I].AsSQLTimeStamp)));
|
|
|
|
|
|
|
|
|
|
ftCurrency:
|
|
|
|
|
AJsonArray.Add(ADataSet.Fields[lField.I].AsCurrency);
|
|
|
|
|
|
|
|
|
|
ftFMTBcd, ftBCD:
|
|
|
|
|
AJsonArray.Add(BcdToDouble(ADataSet.Fields[lField.I].AsBcd));
|
|
|
|
|
|
|
|
|
|
ftGraphic, ftBlob, ftStream, ftOraBlob:
|
|
|
|
|
begin
|
|
|
|
|
lMS := TMemoryStream.Create;
|
|
|
|
|
try
|
|
|
|
|
TBlobField(ADataSet.Fields[lField.I]).SaveToStream(lMS);
|
|
|
|
|
lMS.Position := 0;
|
|
|
|
|
lSS := TStringStream.Create;
|
|
|
|
|
try
|
|
|
|
|
TMVCSerializerHelper.EncodeStream(lMS, lSS);
|
|
|
|
|
AJsonArray.Add(lSS.DataString);
|
|
|
|
|
finally
|
|
|
|
|
lSS.Free;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
lMS.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
ftDataSet:
|
|
|
|
|
begin
|
|
|
|
|
lNestedDataSet := TDataSetField(ADataSet.Fields[lField.I]).NestedDataSet;
|
|
|
|
|
lDataSetFieldsDetail := GetDataSetFields(lNestedDataSet, AIgnoredFields,
|
|
|
|
|
GetNameCase(lNestedDataSet, ncAsIs));
|
|
|
|
|
try
|
|
|
|
|
case GetDataType(ADataSet.Owner, ADataSet.Fields[lField.I].Name, dtArray) of
|
|
|
|
|
dtArray:
|
|
|
|
|
begin
|
|
|
|
|
lChildJsonArray := AJsonArray.AddArray;
|
|
|
|
|
lNestedDataSet.First;
|
|
|
|
|
while not lNestedDataSet.Eof do
|
|
|
|
|
begin
|
2019-11-06 15:08:29 +01:00
|
|
|
|
DataSetRowToJsonArrayOfValues(lNestedDataSet, lChildJsonArray, AIgnoredFields,
|
|
|
|
|
lDataSetFieldsDetail);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
lNestedDataSet.Next;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
dtObject:
|
|
|
|
|
begin
|
|
|
|
|
lChildJsonArray := AJsonArray.AddArray;
|
2019-11-06 15:08:29 +01:00
|
|
|
|
DataSetRowToJsonArrayOfValues(lNestedDataSet, lChildJsonArray, AIgnoredFields,
|
|
|
|
|
lDataSetFieldsDetail);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
lDataSetFieldsDetail.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
else
|
|
|
|
|
raise EMVCSerializationException.CreateFmt('Cannot find type for field "%s"', [lField.FieldName]);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DataSetToJsonArray(const ADataSet: TDataSet; const AJsonArray: TJDOJsonArray;
|
2019-09-25 09:14:09 +02:00
|
|
|
|
const ANameCase: TMVCNameCase; const AIgnoredFields: TMVCIgnoredList;
|
|
|
|
|
const ASerializationCallback: TMVCDataSetFieldSerializationAction);
|
2017-09-07 00:10:21 +02:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
LJObj: TJDOJsonObject;
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lDataSetFields: TMVCDataSetFields;
|
2017-09-07 00:10:21 +02:00
|
|
|
|
begin
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lDataSetFields := GetDataSetFields(ADataSet, AIgnoredFields, ANameCase);
|
|
|
|
|
try
|
|
|
|
|
while not ADataSet.Eof do
|
|
|
|
|
begin
|
|
|
|
|
LJObj := AJsonArray.AddObject;
|
2019-09-25 09:14:09 +02:00
|
|
|
|
DataSetToJsonObject(ADataSet, LJObj, ANameCase, AIgnoredFields, lDataSetFields, ASerializationCallback);
|
2019-04-16 23:12:19 +02:00
|
|
|
|
ADataSet.Next;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
lDataSetFields.Free;
|
2017-09-07 00:10:21 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DataSetToJsonArrayOfValues(const ADataSet: TDataSet;
|
|
|
|
|
const AJsonArray: TJDOJsonArray; const AIgnoredFields: TMVCIgnoredList);
|
|
|
|
|
var
|
|
|
|
|
LJArr: TJDOJsonArray;
|
|
|
|
|
lDataSetFields: TMVCDataSetFields;
|
|
|
|
|
begin
|
|
|
|
|
lDataSetFields := GetDataSetFields(ADataSet, AIgnoredFields, ncAsIs);
|
|
|
|
|
try
|
|
|
|
|
while not ADataSet.Eof do
|
|
|
|
|
begin
|
|
|
|
|
LJArr := AJsonArray.AddArray;
|
|
|
|
|
DataSetRowToJsonArrayOfValues(ADataSet, LJArr, AIgnoredFields, lDataSetFields);
|
|
|
|
|
ADataSet.Next;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
lDataSetFields.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DataSetToJsonObject(const ADataSet: TDataSet; const AJsonObject: TJDOJsonObject;
|
|
|
|
|
const ANameCase: TMVCNameCase; const AIgnoredFields: TMVCIgnoredList; const ADataSetFields: TMVCDataSetFields;
|
|
|
|
|
const ASerializationCallback: TMVCDataSetFieldSerializationAction);
|
2017-03-29 14:49:35 +02:00
|
|
|
|
var
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lMS: TMemoryStream;
|
|
|
|
|
lSS: TStringStream;
|
|
|
|
|
lNestedDataSet: TDataSet;
|
|
|
|
|
lChildJsonArray: TJDOJsonArray;
|
|
|
|
|
lChildJsonObject: TJDOJsonObject;
|
|
|
|
|
lField: TMVCDataSetField;
|
|
|
|
|
lDataSetFieldsDetail: TMVCDataSetFields;
|
2019-09-25 09:14:09 +02:00
|
|
|
|
lHandled: Boolean;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
begin
|
2019-09-30 00:05:46 +02:00
|
|
|
|
Assert(Assigned(ADataSetFields));
|
2019-04-16 23:12:19 +02:00
|
|
|
|
for lField in ADataSetFields do
|
2017-03-29 14:49:35 +02:00
|
|
|
|
begin
|
|
|
|
|
begin
|
2019-09-25 09:14:09 +02:00
|
|
|
|
if Assigned(ASerializationCallback) then
|
|
|
|
|
begin
|
|
|
|
|
lHandled := False;
|
|
|
|
|
ASerializationCallback(ADataSet.Fields[lField.I], AJsonObject, lHandled);
|
|
|
|
|
if lHandled then
|
|
|
|
|
begin
|
|
|
|
|
continue;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-04-17 16:47:07 +02:00
|
|
|
|
if ADataSet.Fields[lField.I].IsNull then
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject[lField.FieldName] := Null
|
2017-03-29 14:49:35 +02:00
|
|
|
|
else
|
|
|
|
|
begin
|
2019-04-16 23:12:19 +02:00
|
|
|
|
case lField.DataType of
|
2017-03-29 14:49:35 +02:00
|
|
|
|
ftBoolean:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.B[lField.FieldName] := ADataSet.Fields[lField.I].AsBoolean;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
2020-03-11 09:03:30 +01:00
|
|
|
|
ftInteger, ftSmallint, ftShortint, ftByte, ftWord:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.I[lField.FieldName] := ADataSet.Fields[lField.I].AsInteger;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
2019-09-01 12:15:30 +02:00
|
|
|
|
ftLargeint, ftAutoInc, ftLongword:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.L[lField.FieldName] := ADataSet.Fields[lField.I].AsLargeInt;
|
2018-01-29 17:30:53 +01:00
|
|
|
|
{$IFDEF TOKYOORBETTER}
|
2017-12-12 20:04:01 +01:00
|
|
|
|
ftGuid:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.S[lField.FieldName] := GUIDToString(ADataSet.Fields[lField.I].AsGuid);
|
2018-01-29 17:30:53 +01:00
|
|
|
|
{$ENDIF}
|
2017-03-29 14:49:35 +02:00
|
|
|
|
ftSingle, ftFloat:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.F[lField.FieldName] := ADataSet.Fields[lField.I].AsFloat;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
2017-09-28 00:14:34 +02:00
|
|
|
|
ftString, ftMemo:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.S[lField.FieldName] := ADataSet.Fields[lField.I].AsString;
|
2017-09-28 00:14:34 +02:00
|
|
|
|
|
|
|
|
|
ftWideString, ftWideMemo:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.S[lField.FieldName] := ADataSet.Fields[lField.I].AsWideString;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
|
|
|
|
ftDate:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.S[lField.FieldName] := DateToISODate(ADataSet.Fields[lField.I].AsDateTime);
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
|
|
|
|
ftDateTime:
|
2019-10-24 15:34:40 +02:00
|
|
|
|
AJsonObject.S[lField.FieldName] := DateTimeToISOTimeStamp(ADataSet.Fields[lField.I].AsDateTime);
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
2017-09-07 00:10:21 +02:00
|
|
|
|
ftTime:
|
2019-10-24 15:34:40 +02:00
|
|
|
|
AJsonObject.S[lField.FieldName] := SQLTimeStampToStr('hh:nn:ss', ADataSet.Fields[lField.I].AsSQLTimeStamp);
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
2017-09-07 00:10:21 +02:00
|
|
|
|
ftTimeStamp:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.S[lField.FieldName] :=
|
2019-10-24 15:34:40 +02:00
|
|
|
|
DateTimeToISOTimeStamp(SQLTimeStampToDateTime(ADataSet.Fields[lField.I].AsSQLTimeStamp));
|
2017-09-07 00:10:21 +02:00
|
|
|
|
|
2017-03-29 14:49:35 +02:00
|
|
|
|
ftCurrency:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.F[lField.FieldName] := ADataSet.Fields[lField.I].AsCurrency;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
|
|
|
|
ftFMTBcd, ftBCD:
|
2019-04-16 23:12:19 +02:00
|
|
|
|
AJsonObject.F[lField.FieldName] := BcdToDouble(ADataSet.Fields[lField.I].AsBcd);
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
2019-02-19 13:04:53 +01:00
|
|
|
|
ftGraphic, ftBlob, ftStream, ftOraBlob:
|
2017-03-29 14:49:35 +02:00
|
|
|
|
begin
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lMS := TMemoryStream.Create;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
try
|
2019-04-16 23:12:19 +02:00
|
|
|
|
TBlobField(ADataSet.Fields[lField.I]).SaveToStream(lMS);
|
|
|
|
|
lMS.Position := 0;
|
|
|
|
|
lSS := TStringStream.Create;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
try
|
2019-04-16 23:12:19 +02:00
|
|
|
|
TMVCSerializerHelper.EncodeStream(lMS, lSS);
|
|
|
|
|
AJsonObject.S[lField.FieldName] := lSS.DataString;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
finally
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lSS.Free;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
end;
|
|
|
|
|
finally
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lMS.Free;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
ftDataSet:
|
|
|
|
|
begin
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lNestedDataSet := TDataSetField(ADataSet.Fields[lField.I]).NestedDataSet;
|
|
|
|
|
lDataSetFieldsDetail := GetDataSetFields(lNestedDataSet, AIgnoredFields,
|
|
|
|
|
GetNameCase(lNestedDataSet, ANameCase));
|
|
|
|
|
try
|
|
|
|
|
case GetDataType(ADataSet.Owner, ADataSet.Fields[lField.I].Name, dtArray) of
|
|
|
|
|
dtArray:
|
2017-03-29 14:49:35 +02:00
|
|
|
|
begin
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lChildJsonArray := AJsonObject.A[lField.FieldName];
|
|
|
|
|
lNestedDataSet.First;
|
|
|
|
|
while not lNestedDataSet.Eof do
|
|
|
|
|
begin
|
|
|
|
|
DataSetToJsonObject(lNestedDataSet, lChildJsonArray.AddObject,
|
2019-10-24 15:34:40 +02:00
|
|
|
|
GetNameCase(lNestedDataSet, ANameCase), AIgnoredFields, lDataSetFieldsDetail,
|
|
|
|
|
ASerializationCallback);
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lNestedDataSet.Next;
|
|
|
|
|
end;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
end;
|
2019-04-16 23:12:19 +02:00
|
|
|
|
dtObject:
|
|
|
|
|
begin
|
|
|
|
|
lChildJsonObject := AJsonObject.O[lField.FieldName];
|
2019-10-24 15:34:40 +02:00
|
|
|
|
DataSetToJsonObject(lNestedDataSet, lChildJsonObject, GetNameCase(lNestedDataSet, ANameCase),
|
|
|
|
|
AIgnoredFields, lDataSetFieldsDetail, ASerializationCallback);
|
2019-04-16 23:12:19 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
lDataSetFieldsDetail.Free;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
else
|
2019-10-24 15:34:40 +02:00
|
|
|
|
raise EMVCSerializationException.CreateFmt('Cannot find type for field "%s"', [lField.FieldName]);
|
2017-03-29 14:49:35 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DeserializeCollection(const ASerializedList: string; const AList: TObject;
|
|
|
|
|
const AClazz: TClass; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JsonArray: TJDOJsonArray;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
ObjList: IMVCList;
|
|
|
|
|
begin
|
|
|
|
|
if (ASerializedList = EmptyStr) then
|
2018-10-31 01:07:23 +01:00
|
|
|
|
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
if not Assigned(AList) then
|
|
|
|
|
Exit;
|
|
|
|
|
|
|
|
|
|
ObjList := TDuckTypedList.Wrap(AList);
|
|
|
|
|
if Assigned(ObjList) then
|
|
|
|
|
begin
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JsonArray := TJDOJsonArray.Parse(ASerializedList) as TJDOJsonArray;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
try
|
|
|
|
|
JsonArrayToList(JsonArray, ObjList, AClazz, AType, AIgnoredAttributes);
|
|
|
|
|
finally
|
|
|
|
|
JsonArray.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-09-18 01:14:54 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DeserializeCollection(const ASerializedList: string; const AList: IInterface;
|
|
|
|
|
const AClazz: TClass; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
|
|
|
|
begin
|
|
|
|
|
DeserializeCollection(ASerializedList, TObject(AList), AClazz, AType, AIgnoredAttributes);
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DeserializeDataSet(const ASerializedDataSet: string; const ADataSet: TDataSet;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
lJsonArray: TJDOJsonArray;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2018-10-31 01:07:23 +01:00
|
|
|
|
if (ASerializedDataSet = EmptyStr) then
|
|
|
|
|
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
|
|
|
|
|
|
|
|
|
|
if not Assigned(ADataSet) then
|
2017-03-30 15:56:24 +02:00
|
|
|
|
Exit;
|
|
|
|
|
|
|
|
|
|
try
|
2019-01-08 12:48:27 +01:00
|
|
|
|
lJsonArray := TJDOJsonArray.Parse(ASerializedDataSet) as TJDOJsonArray;
|
2018-10-31 01:07:23 +01:00
|
|
|
|
except
|
|
|
|
|
on E: EJsonParserException do
|
|
|
|
|
begin
|
|
|
|
|
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
try
|
|
|
|
|
JsonArrayToDataSet(lJsonArray, ADataSet, AIgnoredFields, ANameCase);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
finally
|
2018-10-31 01:07:23 +01:00
|
|
|
|
lJsonArray.Free;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DeserializeDataSetRecord(const ASerializedDataSetRecord: string;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
const ADataSet: TDataSet; const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
var
|
2019-01-18 19:04:01 +01:00
|
|
|
|
lJsonBase: TJDOJsonBaseObject;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
begin
|
|
|
|
|
if (ASerializedDataSetRecord = EmptyStr) or (not Assigned(ADataSet)) then
|
|
|
|
|
Exit;
|
|
|
|
|
|
2019-01-18 19:04:01 +01:00
|
|
|
|
lJsonBase := TJDOJsonObject.Parse(ASerializedDataSetRecord);
|
2018-10-31 01:07:23 +01:00
|
|
|
|
try
|
2019-01-18 19:04:01 +01:00
|
|
|
|
if lJsonBase is TJsonObject then
|
2018-10-31 01:07:23 +01:00
|
|
|
|
begin
|
2019-01-18 19:04:01 +01:00
|
|
|
|
ADataSet.Edit;
|
|
|
|
|
JsonObjectToDataSet(TJsonObject(lJsonBase), ADataSet, AIgnoredFields, ANameCase);
|
|
|
|
|
ADataSet.Post;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
2019-03-05 20:55:37 +01:00
|
|
|
|
raise EMVCSerializationException.Create('Cannot deserialize, expected json object');
|
2018-10-31 01:07:23 +01:00
|
|
|
|
end;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
finally
|
2019-01-18 19:04:01 +01:00
|
|
|
|
lJsonBase.Free;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-09-18 01:14:54 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DeserializeObject(const ASerializedObject: string; const AObject: IInterface;
|
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
|
|
|
|
begin
|
|
|
|
|
DeserializeObject(ASerializedObject, TObject(AObject), AType, AIgnoredAttributes);
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.JsonArrayToArray(const AJsonArray: TJDOJsonArray): TValue;
|
|
|
|
|
var
|
|
|
|
|
I: Integer;
|
|
|
|
|
lStrArr: TArray<String>;
|
|
|
|
|
lIntArr: TArray<Integer>;
|
2019-05-17 16:15:18 +02:00
|
|
|
|
begin
|
|
|
|
|
for I := 0 to Pred(AJsonArray.Count) do
|
|
|
|
|
case AJsonArray.types[0] of
|
2019-10-24 15:34:40 +02:00
|
|
|
|
jdtString:
|
|
|
|
|
lStrArr := lStrArr + [AJsonArray.Items[I].Value];
|
|
|
|
|
jdtInt:
|
|
|
|
|
lIntArr := lIntArr + [AJsonArray.Items[I].Value.ToInteger];
|
2019-05-17 16:15:18 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
if Length(lStrArr) > 0 then
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := TValue.From < TArray < String >> (lStrArr)
|
2019-05-17 16:15:18 +02:00
|
|
|
|
else
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := TValue.From < TArray < Integer >> (lIntArr);
|
2019-05-17 16:15:18 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.JsonArrayToDataSet(const AJsonArray: TJDOJsonArray; const ADataSet: TDataSet;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
|
|
|
|
var
|
|
|
|
|
I: Integer;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
begin
|
2017-03-30 15:56:24 +02:00
|
|
|
|
for I := 0 to Pred(AJsonArray.Count) do
|
|
|
|
|
begin
|
|
|
|
|
ADataSet.Append;
|
|
|
|
|
JsonObjectToDataSet(AJsonArray.Items[I].ObjectValue, ADataSet, AIgnoredFields, ANameCase);
|
|
|
|
|
ADataSet.Post;
|
|
|
|
|
end;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.JsonArrayToList(const AJsonArray: TJDOJsonArray; const AList: IMVCList;
|
|
|
|
|
const AClazz: TClass; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
var
|
|
|
|
|
I: Integer;
|
|
|
|
|
Obj: TObject;
|
|
|
|
|
begin
|
|
|
|
|
for I := 0 to Pred(AJsonArray.Count) do
|
|
|
|
|
begin
|
2018-10-31 01:07:23 +01:00
|
|
|
|
Obj := TMVCSerializerHelper.CreateObject(AClazz.QualifiedClassName);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
JsonObjectToObject(AJsonArray.Items[I].ObjectValue, Obj, GetSerializationType(Obj, AType), AIgnoredAttributes);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
AList.Add(Obj);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.JsonDataValueToAttribute(const AJsonObject: TJDOJsonObject; const AName: string;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
var AValue: TValue; const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
const ACustomAttributes: TArray<TCustomAttribute>);
|
|
|
|
|
var
|
|
|
|
|
ChildObject: TObject;
|
|
|
|
|
ChildList: IMVCList;
|
|
|
|
|
ChildListOfAtt: MVCListOfAttribute;
|
2020-03-12 20:37:48 +01:00
|
|
|
|
LEnumAsAttr: MVCEnumSerializationAttribute;
|
2020-03-12 18:24:20 +01:00
|
|
|
|
LEnumMappedValues: TList<string>;
|
|
|
|
|
LEnumSerType: TMVCEnumSerializationType;
|
2019-10-14 23:11:08 +02:00
|
|
|
|
LClazz: TClass;
|
2020-03-12 18:24:20 +01:00
|
|
|
|
LMappedValueIndex: Integer;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2017-03-02 12:57:40 +01:00
|
|
|
|
if GetTypeSerializers.ContainsKey(AValue.TypeInfo) then
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
|
|
|
|
case AJsonObject[AName].Typ of
|
|
|
|
|
jdtNone:
|
|
|
|
|
Exit;
|
|
|
|
|
jdtObject:
|
2019-01-10 17:30:40 +01:00
|
|
|
|
begin
|
|
|
|
|
/// <summary>JsonDataObjects assumes values null as jdtObject</summary>
|
|
|
|
|
if AJsonObject[AName].ObjectValue <> nil then
|
2019-03-05 20:55:37 +01:00
|
|
|
|
GetTypeSerializers.Items[AValue.TypeInfo].DeserializeAttribute(AValue, AName,
|
|
|
|
|
AJsonObject[AName].ObjectValue, ACustomAttributes);
|
2019-01-10 17:30:40 +01:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
jdtArray:
|
2019-10-24 15:34:40 +02:00
|
|
|
|
GetTypeSerializers.Items[AValue.TypeInfo].DeserializeAttribute(AValue, AName, AJsonObject[AName].ArrayValue,
|
2018-12-12 11:00:41 +01:00
|
|
|
|
ACustomAttributes);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
else
|
2019-10-24 15:34:40 +02:00
|
|
|
|
GetTypeSerializers.Items[AValue.TypeInfo].DeserializeAttribute(AValue, AName, AJsonObject, ACustomAttributes);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
case AJsonObject[AName].Typ of
|
|
|
|
|
jdtNone:
|
|
|
|
|
Exit;
|
|
|
|
|
|
|
|
|
|
jdtString:
|
|
|
|
|
begin
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(TDate)) then
|
|
|
|
|
AValue := TValue.From<TDate>(ISODateToDate(AJsonObject[AName].Value))
|
|
|
|
|
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if (AValue.TypeInfo = System.TypeInfo(TDateTime)) then
|
2019-05-16 00:16:55 +02:00
|
|
|
|
AValue := TValue.From<TDateTime>(ISOTimeStampToDateTime(AJsonObject[AName].Value))
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if (AValue.TypeInfo = System.TypeInfo(TTime)) then
|
2019-05-16 00:16:55 +02:00
|
|
|
|
AValue := TValue.From<TTime>(ISOTimeToTime(AJsonObject[AName].Value))
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
2020-02-03 12:11:42 +01:00
|
|
|
|
else if (AValue.Kind = tkRecord) and (AValue.TypeInfo <> TypeInfo(TValue)) then { nullables }
|
|
|
|
|
begin
|
|
|
|
|
if AValue.TypeInfo = TypeInfo(NullableString) then
|
|
|
|
|
begin
|
|
|
|
|
AValue := TValue.From<NullableString>(NullableString(AJsonObject[AName].Value))
|
|
|
|
|
end
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableTDate) then
|
|
|
|
|
begin
|
|
|
|
|
AValue := TValue.From<NullableTDate>(NullableTDate(ISODateToDate(AJsonObject[AName].Value)))
|
|
|
|
|
end
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableTDateTime) then
|
|
|
|
|
begin
|
|
|
|
|
AValue := TValue.From<NullableTDateTime>
|
|
|
|
|
(NullableTDateTime(ISOTimeStampToDateTime(AJsonObject[AName].Value)))
|
|
|
|
|
end
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableTTime) then
|
|
|
|
|
begin
|
|
|
|
|
AValue := TValue.From<NullableTTime>(NullableTTime(ISOTimeToTime(AJsonObject[AName].Value)))
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
raise EMVCSerializationException.CreateFmt('Cannot deserialize property %s from string', [AName]);
|
|
|
|
|
end
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if (AValue.Kind = tkEnumeration) then
|
2019-10-24 15:34:40 +02:00
|
|
|
|
begin
|
2020-03-12 21:19:30 +01:00
|
|
|
|
LEnumSerType := estEnumName;
|
|
|
|
|
LEnumMappedValues := nil;
|
|
|
|
|
if TMVCSerializerHelper.AttributeExists<MVCEnumSerializationAttribute>(ACustomAttributes, LEnumAsAttr) then
|
2020-03-12 18:24:20 +01:00
|
|
|
|
begin
|
|
|
|
|
LEnumSerType := LEnumAsAttr.SerializationType;
|
|
|
|
|
LEnumMappedValues := LEnumAsAttr.MappedValues;
|
|
|
|
|
end;
|
2017-07-12 11:39:16 +02:00
|
|
|
|
|
2020-03-12 18:24:20 +01:00
|
|
|
|
if LEnumSerType = estEnumName then
|
|
|
|
|
begin
|
|
|
|
|
TValue.Make(GetEnumValue(AValue.TypeInfo, AJsonObject[AName].Value), AValue.TypeInfo, AValue)
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
LMappedValueIndex := LEnumMappedValues.IndexOf(AJsonObject[AName].Value);
|
|
|
|
|
TValue.Make(GetEnumValue(AValue.TypeInfo, GetEnumName(AValue.TypeInfo, LMappedValueIndex)),
|
|
|
|
|
AValue.TypeInfo, AValue)
|
|
|
|
|
end;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
end
|
2019-05-16 00:16:55 +02:00
|
|
|
|
else
|
|
|
|
|
AValue := TValue.From<string>(AJsonObject[AName].Value);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
jdtInt:
|
|
|
|
|
begin
|
2019-08-12 21:48:33 +02:00
|
|
|
|
if (AValue.Kind = tkEnumeration) then
|
|
|
|
|
begin
|
|
|
|
|
TValue.Make(GetEnumValue(AValue.TypeInfo, GetEnumName(AValue.TypeInfo, AJsonObject[AName].IntValue)),
|
|
|
|
|
AValue.TypeInfo, AValue)
|
|
|
|
|
end
|
2020-02-03 10:51:40 +01:00
|
|
|
|
else if (AValue.Kind <> tkRecord) then { nullables }
|
2019-08-12 21:48:33 +02:00
|
|
|
|
begin
|
|
|
|
|
AValue := TValue.From<Integer>(AJsonObject[AName].IntValue);
|
2020-02-03 10:51:40 +01:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if AValue.TypeInfo = TypeInfo(NullableInt32) then
|
|
|
|
|
AValue := TValue.From<NullableInt32>(NullableInt32(AJsonObject[AName].IntValue))
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableUInt32) then
|
|
|
|
|
AValue := TValue.From<NullableUInt32>(NullableUInt32(AJsonObject[AName].IntValue))
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableInt16) then
|
|
|
|
|
AValue := TValue.From<NullableInt16>(NullableInt16(AJsonObject[AName].IntValue))
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableUInt16) then
|
|
|
|
|
AValue := TValue.From<NullableUInt16>(NullableUInt16(AJsonObject[AName].IntValue))
|
2020-02-03 12:11:42 +01:00
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableInt64) then
|
|
|
|
|
AValue := TValue.From<NullableInt64>(NullableInt64(AJsonObject[AName].LongValue))
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableUInt64) then
|
|
|
|
|
AValue := TValue.From<NullableUInt64>(NullableUInt64(AJsonObject[AName].LongValue))
|
2020-02-03 10:51:40 +01:00
|
|
|
|
else
|
|
|
|
|
raise EMVCDeserializationException.CreateFmt('Cannot deserialize integer value for ', [AName]);
|
2019-08-12 21:48:33 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
jdtLong, jdtULong:
|
|
|
|
|
begin
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(TTimeStamp)) then
|
2020-02-03 10:51:40 +01:00
|
|
|
|
begin
|
2017-03-01 21:40:57 +01:00
|
|
|
|
AValue := TValue.From<TTimeStamp>(MSecsToTimeStamp(AJsonObject[AName].LongValue))
|
2020-02-03 10:51:40 +01:00
|
|
|
|
end
|
|
|
|
|
else if (AValue.Kind <> tkRecord) then { nullables }
|
|
|
|
|
begin
|
2017-03-01 21:40:57 +01:00
|
|
|
|
AValue := TValue.From<Int64>(AJsonObject[AName].LongValue);
|
2020-02-03 10:51:40 +01:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if AValue.TypeInfo = TypeInfo(NullableInt64) then
|
|
|
|
|
AValue := TValue.From<NullableInt64>(NullableInt64(AJsonObject[AName].LongValue))
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableUInt64) then
|
|
|
|
|
AValue := TValue.From<NullableUInt64>(NullableUInt64(AJsonObject[AName].LongValue))
|
|
|
|
|
else
|
|
|
|
|
raise EMVCDeserializationException.CreateFmt('Cannot deserialize long integer value for ', [AName]);
|
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
jdtFloat:
|
2020-02-03 10:51:40 +01:00
|
|
|
|
if (AValue.Kind <> tkRecord) then { nullables }
|
|
|
|
|
begin
|
|
|
|
|
AValue := TValue.From<Double>(AJsonObject[AName].FloatValue);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if AValue.TypeInfo = TypeInfo(NullableSingle) then
|
|
|
|
|
AValue := TValue.From<NullableSingle>(NullableSingle(AJsonObject[AName].FloatValue))
|
2020-02-03 12:11:42 +01:00
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableCurrency) then
|
|
|
|
|
AValue := TValue.From<NullableCurrency>(NullableCurrency(AJsonObject[AName].FloatValue))
|
2020-02-03 10:51:40 +01:00
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableDouble) then
|
|
|
|
|
AValue := TValue.From<NullableDouble>(NullableDouble(AJsonObject[AName].FloatValue))
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableExtended) then
|
|
|
|
|
AValue := TValue.From<NullableExtended>(NullableExtended(AJsonObject[AName].FloatValue))
|
|
|
|
|
else
|
2020-02-03 12:11:42 +01:00
|
|
|
|
raise EMVCDeserializationException.CreateFmt('Cannot deserialize floating-point value for %s', [AName]);
|
2020-02-03 10:51:40 +01:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
jdtDateTime:
|
2020-02-03 10:51:40 +01:00
|
|
|
|
if (AValue.Kind <> tkRecord) then { nullables }
|
|
|
|
|
begin
|
|
|
|
|
AValue := TValue.From<TDateTime>(AJsonObject[AName].DateTimeValue);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if AValue.TypeInfo = TypeInfo(NullableTDate) then
|
|
|
|
|
AValue := TValue.From<NullableTDate>(NullableTDate(AJsonObject[AName].DateTimeValue))
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableTDateTime) then
|
|
|
|
|
AValue := TValue.From<NullableTDateTime>(NullableTDateTime(AJsonObject[AName].DateTimeValue))
|
|
|
|
|
else if AValue.TypeInfo = TypeInfo(NullableTTime) then
|
|
|
|
|
AValue := TValue.From<NullableTTime>(NullableTTime(AJsonObject[AName].DateTimeValue))
|
|
|
|
|
else
|
|
|
|
|
raise EMVCDeserializationException.CreateFmt('Cannot deserialize date or time value for ', [AName]);
|
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
jdtBool:
|
2020-02-03 10:51:40 +01:00
|
|
|
|
if (AValue.Kind <> tkRecord) then { nullables }
|
|
|
|
|
begin
|
|
|
|
|
AValue := TValue.From<Boolean>(AJsonObject[AName].BoolValue);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
if AValue.TypeInfo = TypeInfo(NullableBoolean) then
|
|
|
|
|
AValue := TValue.From<NullableBoolean>(NullableBoolean(AJsonObject[AName].BoolValue))
|
|
|
|
|
else
|
|
|
|
|
raise EMVCDeserializationException.CreateFmt('Cannot deserialize boolean value for ', [AName]);
|
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
jdtObject:
|
|
|
|
|
begin
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(TValue)) then
|
|
|
|
|
AValue := TValue.FromVariant(AJsonObject[AName].O['value'].VariantValue)
|
|
|
|
|
else
|
|
|
|
|
begin
|
2017-05-17 22:32:45 +02:00
|
|
|
|
// dt: if a key is null, jsondataobjects assign it the type jdtObject
|
2017-05-18 00:02:22 +02:00
|
|
|
|
if AJsonObject[AName].ObjectValue <> nil then
|
2017-05-17 22:32:45 +02:00
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
if AValue.Kind = tkInterface then
|
2019-09-18 13:30:50 +02:00
|
|
|
|
ChildObject := TObject(AValue.AsInterface)
|
|
|
|
|
else
|
|
|
|
|
ChildObject := AValue.AsObject;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
JsonObjectToObject(AJsonObject.O[AName], ChildObject, GetSerializationType(ChildObject, AType), AIgnored);
|
2017-05-17 22:32:45 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
jdtArray:
|
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
if AValue.Kind = tkInterface then
|
2019-09-18 13:30:50 +02:00
|
|
|
|
ChildObject := TObject(AValue.AsInterface)
|
|
|
|
|
else
|
|
|
|
|
ChildObject := AValue.AsObject;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
if Assigned(ChildObject) then
|
|
|
|
|
begin
|
2019-02-22 18:19:07 +01:00
|
|
|
|
if ChildObject is TDataSet then
|
|
|
|
|
JsonArrayToDataSet(AJsonObject.A[AName], ChildObject as TDataSet, AIgnored, ncLowerCase)
|
2017-03-01 21:40:57 +01:00
|
|
|
|
else
|
2019-02-22 18:19:07 +01:00
|
|
|
|
begin
|
|
|
|
|
ChildList := TDuckTypedList.Wrap(ChildObject);
|
2019-10-14 23:11:08 +02:00
|
|
|
|
|
|
|
|
|
if TMVCSerializerHelper.AttributeExists<MVCListOfAttribute>(ACustomAttributes, ChildListOfAtt) then
|
|
|
|
|
LClazz := ChildListOfAtt.Value
|
|
|
|
|
else
|
|
|
|
|
LClazz := GetObjectTypeOfGenericList(AValue.TypeInfo);
|
|
|
|
|
|
|
|
|
|
if Assigned(LClazz) then
|
|
|
|
|
JsonArrayToList(AJsonObject.A[AName], ChildList, LClazz, AType, AIgnored)
|
2019-02-22 18:19:07 +01:00
|
|
|
|
else
|
|
|
|
|
raise EMVCDeserializationException.CreateFmt
|
2019-03-05 20:55:37 +01:00
|
|
|
|
('You can not deserialize a list %s without the MVCListOf attribute.', [AName]);
|
2019-02-22 18:19:07 +01:00
|
|
|
|
end;
|
2019-05-17 16:15:18 +02:00
|
|
|
|
end
|
|
|
|
|
else if AValue.isArray then
|
2019-09-18 13:30:50 +02:00
|
|
|
|
begin
|
2019-05-17 16:15:18 +02:00
|
|
|
|
AValue := JsonArrayToArray(AJsonObject.A[AName]);
|
2019-09-18 13:30:50 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.JsonObjectToDataSet(const AJsonObject: TJDOJsonObject; const ADataSet: TDataSet;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase);
|
|
|
|
|
var
|
|
|
|
|
Field: TField;
|
|
|
|
|
Name: string;
|
|
|
|
|
SS: TStringStream;
|
|
|
|
|
SM: TMemoryStream;
|
|
|
|
|
NestedDataSet: TDataSet;
|
|
|
|
|
begin
|
|
|
|
|
if (ADataSet.State in [dsInsert, dsEdit]) then
|
|
|
|
|
begin
|
|
|
|
|
for Field in ADataSet.Fields do
|
|
|
|
|
begin
|
2017-05-17 22:32:45 +02:00
|
|
|
|
name := GetNameAs(ADataSet.Owner, Field.Name, Field.FieldName);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
if (IsIgnoredAttribute(AIgnoredFields, name)) or (IsIgnoredComponent(ADataSet.Owner, Field.Name)) then
|
|
|
|
|
continue;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
case GetNameCase(ADataSet, ANameCase) of
|
2018-10-14 18:23:20 +02:00
|
|
|
|
ncLowerCase:
|
|
|
|
|
name := LowerCase(Field.FieldName);
|
|
|
|
|
ncUpperCase:
|
|
|
|
|
name := UpperCase(Field.FieldName);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2017-05-17 22:32:45 +02:00
|
|
|
|
if not AJsonObject.Contains(name) then
|
2019-10-24 15:34:40 +02:00
|
|
|
|
continue;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
2019-03-10 16:29:18 +01:00
|
|
|
|
if (AJsonObject[name].Typ = jdtObject) and (AJsonObject.Values[name].ObjectValue = nil) then
|
|
|
|
|
// Nullable Type
|
2017-03-30 15:56:24 +02:00
|
|
|
|
begin
|
|
|
|
|
Field.Clear;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
continue;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2018-10-14 18:23:20 +02:00
|
|
|
|
case Field.DataType of
|
2017-03-30 15:56:24 +02:00
|
|
|
|
TFieldType.ftBoolean:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsBoolean := AJsonObject.B[name];
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
2020-02-03 10:51:40 +01:00
|
|
|
|
TFieldType.ftInteger, TFieldType.ftSmallint, TFieldType.ftShortint, TFieldType.ftByte, TFieldType.ftLongword,
|
|
|
|
|
TFieldType.ftWord, TFieldType.ftAutoInc:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsInteger := AJsonObject.I[name];
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
TFieldType.ftLargeint:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsLargeInt := AJsonObject.L[name];
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
TFieldType.ftCurrency:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsCurrency := AJsonObject.F[name];
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
TFieldType.ftSingle:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsSingle := AJsonObject.F[name];
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
TFieldType.ftFloat, TFieldType.ftFMTBcd, TFieldType.ftBCD:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsFloat := AJsonObject.F[name];
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
ftString, ftWideString, ftMemo, ftWideMemo:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsWideString := AJsonObject.S[name];
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
TFieldType.ftDate:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsDateTime := ISODateToDate(AJsonObject.S[name]);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
TFieldType.ftDateTime:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsDateTime := ISOTimeStampToDateTime(AJsonObject.S[name]);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
|
|
|
|
TFieldType.ftTimeStamp, TFieldType.ftTime:
|
2017-05-17 22:32:45 +02:00
|
|
|
|
Field.AsDateTime := ISOTimeToTime(AJsonObject.S[name]);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
|
2018-01-29 17:30:53 +01:00
|
|
|
|
{$IFDEF TOKYOORBETTER}
|
2017-12-12 20:04:01 +01:00
|
|
|
|
TFieldType.ftGuid:
|
|
|
|
|
Field.AsGuid := StringToGUID(AJsonObject.S[name]);
|
2018-01-29 17:30:53 +01:00
|
|
|
|
{$ENDIF}
|
2017-03-30 15:56:24 +02:00
|
|
|
|
TFieldType.ftGraphic, TFieldType.ftBlob, TFieldType.ftStream:
|
|
|
|
|
begin
|
2017-05-17 22:32:45 +02:00
|
|
|
|
SS := TStringStream.Create(AJsonObject.S[name]);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
try
|
|
|
|
|
SS.Position := 0;
|
|
|
|
|
SM := TMemoryStream.Create;
|
|
|
|
|
try
|
2018-10-31 01:07:23 +01:00
|
|
|
|
TMVCSerializerHelper.DecodeStream(SS, SM);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
TBlobField(Field).LoadFromStream(SM);
|
|
|
|
|
finally
|
|
|
|
|
SM.Free;
|
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
SS.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
TFieldType.ftDataSet:
|
|
|
|
|
begin
|
|
|
|
|
NestedDataSet := TDataSetField(Field).NestedDataSet;
|
|
|
|
|
|
|
|
|
|
NestedDataSet.First;
|
|
|
|
|
while not NestedDataSet.Eof do
|
|
|
|
|
NestedDataSet.Delete;
|
|
|
|
|
|
|
|
|
|
case GetDataType(ADataSet.Owner, Field.Name, dtArray) of
|
|
|
|
|
dtArray:
|
|
|
|
|
begin
|
2017-05-17 22:32:45 +02:00
|
|
|
|
JsonArrayToDataSet(AJsonObject.A[name], NestedDataSet, AIgnoredFields, ANameCase);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
end;
|
|
|
|
|
dtObject:
|
|
|
|
|
begin
|
|
|
|
|
NestedDataSet.Edit;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
JsonObjectToDataSet(AJsonObject.O[name], NestedDataSet, AIgnoredFields, ANameCase);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
NestedDataSet.Post;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
else
|
2019-10-24 15:34:40 +02:00
|
|
|
|
raise EMVCDeserializationException.CreateFmt('Cannot find type for field "%s"', [Field.FieldName]);
|
2017-03-30 15:56:24 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
var
|
|
|
|
|
ObjType: TRttiType;
|
|
|
|
|
Prop: TRttiProperty;
|
|
|
|
|
Fld: TRttiField;
|
|
|
|
|
AttributeValue: TValue;
|
2018-08-05 20:31:33 +02:00
|
|
|
|
lKeyName: string;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2019-11-05 14:40:39 +01:00
|
|
|
|
if AObject is TJsonObject then
|
|
|
|
|
begin
|
|
|
|
|
if not Assigned(AObject) then
|
|
|
|
|
begin
|
|
|
|
|
raise EMVCDeserializationException.Create(AObject.ClassName + ' is not assigned');
|
|
|
|
|
end;
|
|
|
|
|
TJsonObject(AObject).Assign(AJsonObject);
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-02 12:57:40 +01:00
|
|
|
|
ObjType := GetRttiContext.GetType(AObject.ClassType);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
case AType of
|
|
|
|
|
stDefault, stProperties:
|
|
|
|
|
begin
|
2018-10-14 18:23:20 +02:00
|
|
|
|
try
|
|
|
|
|
for Prop in ObjType.GetProperties do
|
|
|
|
|
begin
|
2017-05-25 12:30:08 +02:00
|
|
|
|
|
2018-07-16 12:34:07 +02:00
|
|
|
|
{$IFDEF AUTOREFCOUNT}
|
2018-11-21 22:11:58 +01:00
|
|
|
|
if TMVCSerializerHelper.IsAPropertyToSkip(Prop.Name) then
|
2019-10-24 15:34:40 +02:00
|
|
|
|
continue;
|
2017-05-25 12:30:08 +02:00
|
|
|
|
|
2018-07-16 12:34:07 +02:00
|
|
|
|
{$ENDIF}
|
2018-10-14 18:23:20 +02:00
|
|
|
|
if (Prop.IsWritable or Prop.GetValue(AObject).IsObject) and
|
2018-10-31 01:07:23 +01:00
|
|
|
|
(not TMVCSerializerHelper.HasAttribute<MVCDoNotSerializeAttribute>(Prop)) and
|
2018-10-14 18:23:20 +02:00
|
|
|
|
(not IsIgnoredAttribute(AIgnoredAttributes, Prop.Name)) then
|
|
|
|
|
begin
|
|
|
|
|
AttributeValue := Prop.GetValue(AObject);
|
2018-10-31 01:07:23 +01:00
|
|
|
|
lKeyName := TMVCSerializerHelper.GetKeyName(Prop, ObjType);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
JsonDataValueToAttribute(AJsonObject, lKeyName, AttributeValue, AType, AIgnoredAttributes,
|
2018-12-12 11:00:41 +01:00
|
|
|
|
Prop.GetAttributes);
|
2018-10-14 18:23:20 +02:00
|
|
|
|
if (not AttributeValue.IsEmpty) and Prop.IsWritable then
|
|
|
|
|
Prop.SetValue(AObject, AttributeValue);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
except
|
|
|
|
|
on E: EInvalidCast do
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2018-10-14 18:23:20 +02:00
|
|
|
|
raise EMVCException.CreateFmt('Invalid class typecast for property "%s"', [lKeyName]);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
2017-05-25 12:30:08 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
stFields:
|
|
|
|
|
begin
|
2018-08-05 20:31:33 +02:00
|
|
|
|
try
|
|
|
|
|
for Fld in ObjType.GetFields do
|
2018-10-31 01:07:23 +01:00
|
|
|
|
if (not TMVCSerializerHelper.HasAttribute<MVCDoNotSerializeAttribute>(Fld)) and
|
2018-08-05 20:31:33 +02:00
|
|
|
|
(not IsIgnoredAttribute(AIgnoredAttributes, Fld.Name)) then
|
|
|
|
|
begin
|
|
|
|
|
AttributeValue := Fld.GetValue(AObject);
|
2018-10-31 01:07:23 +01:00
|
|
|
|
lKeyName := TMVCSerializerHelper.GetKeyName(Fld, ObjType);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
JsonDataValueToAttribute(AJsonObject, lKeyName, AttributeValue, AType, AIgnoredAttributes,
|
2018-12-12 11:00:41 +01:00
|
|
|
|
Fld.GetAttributes);
|
2018-08-05 20:31:33 +02:00
|
|
|
|
if not AttributeValue.IsEmpty then
|
|
|
|
|
Fld.SetValue(AObject, AttributeValue);
|
|
|
|
|
end;
|
|
|
|
|
except
|
|
|
|
|
on E: EInvalidCast do
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2018-08-05 20:31:33 +02:00
|
|
|
|
raise EMVCException.CreateFmt('Invalid class typecast for field "%s"', [lKeyName]);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
2018-08-05 20:31:33 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.ListToJsonArray(const AList: IMVCList; const AJsonArray: TJDOJsonArray;
|
2019-03-08 09:33:41 +01:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
|
|
|
|
|
const ASerializationAction: TMVCSerializationAction);
|
2018-10-23 16:18:34 +02:00
|
|
|
|
var
|
|
|
|
|
I: Integer;
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lDict: IMVCLinks;
|
2019-03-08 09:33:41 +01:00
|
|
|
|
lSer: IMVCTypeSerializer;
|
2018-10-23 16:18:34 +02:00
|
|
|
|
begin
|
|
|
|
|
if not Assigned(AList) then
|
|
|
|
|
raise EMVCSerializationException.Create('List not assigned');
|
2019-03-08 09:33:41 +01:00
|
|
|
|
if Assigned(ASerializationAction) then
|
2018-10-23 16:18:34 +02:00
|
|
|
|
begin
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lDict := TJDOLinks.Create;
|
|
|
|
|
for I := 0 to Pred(AList.Count) do
|
|
|
|
|
begin
|
|
|
|
|
lDict.Clear;
|
|
|
|
|
InternalObjectToJsonObject(AList.GetItem(I), AJsonArray.AddObject, AType, AIgnoredAttributes,
|
|
|
|
|
ASerializationAction, lDict, lSer);
|
2019-03-08 09:33:41 +01:00
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
for I := 0 to Pred(AList.Count) do
|
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
InternalObjectToJsonObject(AList.GetItem(I), AJsonArray.AddObject, AType, AIgnoredAttributes, nil, nil, nil);
|
2019-03-08 09:33:41 +01:00
|
|
|
|
end;
|
2018-10-23 16:18:34 +02:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.ObjectToJsonObject(const AObject: TObject; const AJsonObject: TJDOJsonObject;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2019-03-08 09:33:41 +01:00
|
|
|
|
begin
|
|
|
|
|
InternalObjectToJsonObject(AObject, AJsonObject, AType, AIgnoredAttributes, nil, nil, nil);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.InternalObjectToJsonObject(const AObject: TObject;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const AJsonObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
|
|
|
|
|
const ASerializationAction: TMVCSerializationAction; const Links: IMVCLinks; const Serializer: IMVCTypeSerializer);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
var
|
|
|
|
|
ObjType: TRttiType;
|
|
|
|
|
Prop: TRttiProperty;
|
|
|
|
|
Fld: TRttiField;
|
|
|
|
|
begin
|
2019-03-08 09:33:41 +01:00
|
|
|
|
{ TODO -oDanieleT -cGeneral : Find a way to automatically add HATEOS }
|
2017-03-02 12:57:40 +01:00
|
|
|
|
ObjType := GetRttiContext.GetType(AObject.ClassType);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
case AType of
|
|
|
|
|
stDefault, stProperties:
|
|
|
|
|
begin
|
|
|
|
|
for Prop in ObjType.GetProperties do
|
2017-05-25 12:30:08 +02:00
|
|
|
|
begin
|
|
|
|
|
|
2018-07-16 12:34:07 +02:00
|
|
|
|
{$IFDEF AUTOREFCOUNT}
|
2018-11-21 22:11:58 +01:00
|
|
|
|
if TMVCSerializerHelper.IsAPropertyToSkip(Prop.Name) then
|
2019-10-24 15:34:40 +02:00
|
|
|
|
continue;
|
2017-05-25 12:30:08 +02:00
|
|
|
|
|
2018-07-16 12:34:07 +02:00
|
|
|
|
{$ENDIF}
|
2018-10-31 01:07:23 +01:00
|
|
|
|
if (not TMVCSerializerHelper.HasAttribute<MVCDoNotSerializeAttribute>(Prop)) and
|
2018-07-16 12:34:07 +02:00
|
|
|
|
(not IsIgnoredAttribute(AIgnoredAttributes, Prop.Name)) then
|
2018-10-31 01:07:23 +01:00
|
|
|
|
AttributeToJsonDataValue(AJsonObject, TMVCSerializerHelper.GetKeyName(Prop, ObjType),
|
2018-07-16 12:34:07 +02:00
|
|
|
|
Prop.GetValue(AObject), AType, AIgnoredAttributes, Prop.GetAttributes);
|
2017-05-25 12:30:08 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
stFields:
|
|
|
|
|
begin
|
|
|
|
|
for Fld in ObjType.GetFields do
|
2019-07-07 17:25:11 +02:00
|
|
|
|
begin
|
2018-10-31 01:07:23 +01:00
|
|
|
|
if (not TMVCSerializerHelper.HasAttribute<MVCDoNotSerializeAttribute>(Fld)) and
|
2018-07-16 12:34:07 +02:00
|
|
|
|
(not IsIgnoredAttribute(AIgnoredAttributes, Fld.Name)) then
|
2019-10-24 15:34:40 +02:00
|
|
|
|
AttributeToJsonDataValue(AJsonObject, TMVCSerializerHelper.GetKeyName(Fld, ObjType), Fld.GetValue(AObject),
|
2018-07-16 12:34:07 +02:00
|
|
|
|
AType, AIgnoredAttributes, Fld.GetAttributes);
|
2019-07-07 17:25:11 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
2019-03-08 09:33:41 +01:00
|
|
|
|
|
|
|
|
|
if Assigned(ASerializationAction) then
|
|
|
|
|
begin
|
2019-05-09 20:53:52 +02:00
|
|
|
|
ASerializationAction(AObject, Links);
|
|
|
|
|
TJDOLinks(Links).FillJSONArray(AJsonObject.A[TMVCConstants.HATEOAS_PROP_NAME]);
|
2019-03-08 09:33:41 +01:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2018-10-23 16:18:34 +02:00
|
|
|
|
class function TMVCJsonDataObjectsSerializer.Parse<T>(const AString: string): T;
|
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := TJDOJsonObject.Parse(AString) as T;
|
|
|
|
|
if not Assigned(Result) then
|
2018-10-23 16:18:34 +02:00
|
|
|
|
raise EMVCDeserializationException.Create('Cannot parse string as ' + T.ClassName);
|
|
|
|
|
end;
|
|
|
|
|
|
2019-01-08 12:48:27 +01:00
|
|
|
|
class function TMVCJsonDataObjectsSerializer.ParseArray(const AString: string): TJDOJsonArray;
|
2018-10-23 16:18:34 +02:00
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := Parse<TJDOJsonArray>(AString);
|
2018-10-23 16:18:34 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2019-01-08 12:48:27 +01:00
|
|
|
|
class function TMVCJsonDataObjectsSerializer.ParseObject(const AString: string): TJDOJsonObject;
|
2018-10-23 16:18:34 +02:00
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := Parse<TJDOJsonObject>(AString);
|
2018-10-23 16:18:34 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.SerializeCollection(const AList: TObject; const AType: TMVCSerializationType;
|
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): string;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JsonArray: TJDOJsonArray;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
ObjList: IMVCList;
|
|
|
|
|
Obj: TObject;
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lLinks: IMVCLinks;
|
2019-03-08 09:33:41 +01:00
|
|
|
|
lSer: IMVCTypeSerializer;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := EmptyStr;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
if not Assigned(AList) then
|
|
|
|
|
Exit;
|
|
|
|
|
|
|
|
|
|
if AList is TJsonBaseObject then
|
2017-05-25 10:31:24 +02:00
|
|
|
|
Exit(TJsonBaseObject(AList).ToJSON(True));
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
ObjList := TDuckTypedList.Wrap(AList);
|
|
|
|
|
if Assigned(ObjList) then
|
|
|
|
|
begin
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JsonArray := TJDOJsonArray.Create;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
try
|
2019-03-08 09:33:41 +01:00
|
|
|
|
if Assigned(ASerializationAction) then
|
|
|
|
|
begin
|
|
|
|
|
if not GetTypeSerializers.TryGetValue(TypeInfo(TMVCStringDictionary), lSer) then
|
|
|
|
|
begin
|
|
|
|
|
raise EMVCSerializationException.Create
|
|
|
|
|
('Cannot serialize _links without TMVCStringDictionary custom serializer');
|
|
|
|
|
end;
|
|
|
|
|
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lLinks := TJDOLinks.Create;
|
|
|
|
|
for Obj in ObjList do
|
|
|
|
|
begin
|
|
|
|
|
lLinks.Clear;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
InternalObjectToJsonObject(Obj, JsonArray.AddObject, GetSerializationType(Obj, AType), AIgnoredAttributes,
|
2019-05-09 20:53:52 +02:00
|
|
|
|
ASerializationAction, lLinks, lSer);
|
2019-03-08 09:33:41 +01:00
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else
|
2018-12-12 11:00:41 +01:00
|
|
|
|
begin
|
2019-03-08 09:33:41 +01:00
|
|
|
|
for Obj in ObjList do
|
2018-12-12 11:00:41 +01:00
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
ObjectToJsonObject(Obj, JsonArray.AddObject, GetSerializationType(Obj, AType), AIgnoredAttributes);
|
2018-12-12 11:00:41 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := JsonArray.ToJSON(True);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
finally
|
|
|
|
|
JsonArray.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-09-18 01:14:54 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.SerializeCollection(const AList: IInterface; const AType: TMVCSerializationType;
|
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): string;
|
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := SerializeCollection(TObject(AList), AType, AIgnoredAttributes, ASerializationAction);
|
2019-09-18 01:14:54 +02:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.SerializeDataSet(const ADataSet: TDataSet;
|
|
|
|
|
const AIgnoredFields: TMVCIgnoredList = []; const ANameCase: TMVCNameCase = ncAsIs;
|
2019-03-10 16:29:18 +01:00
|
|
|
|
const ASerializationAction: TMVCDatasetSerializationAction = nil): string;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JsonArray: TJDOJsonArray;
|
2017-03-30 15:56:24 +02:00
|
|
|
|
BookMark: TBookmark;
|
2018-10-30 13:53:01 +01:00
|
|
|
|
lNameCase: TMVCNameCase;
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lLinks: IMVCLinks;
|
2019-03-10 16:29:18 +01:00
|
|
|
|
LJObj: TJsonObject;
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lDataSetFields: TMVCDataSetFields;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := EmptyStr;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
2019-05-19 11:06:03 +02:00
|
|
|
|
if (not Assigned(ADataSet)) then
|
|
|
|
|
Exit('null');
|
|
|
|
|
if ADataSet.IsEmpty then
|
|
|
|
|
Exit('[]'); // https://github.com/danieleteti/delphimvcframework/issues/219
|
2017-03-29 14:49:35 +02:00
|
|
|
|
|
2019-03-10 16:29:18 +01:00
|
|
|
|
lLinks := nil;
|
|
|
|
|
if Assigned(ASerializationAction) then
|
|
|
|
|
begin
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lLinks := TJDOLinks.Create;
|
2019-03-10 16:29:18 +01:00
|
|
|
|
end;
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lDataSetFields := GetDataSetFields(ADataSet, AIgnoredFields, ANameCase);
|
2017-03-29 14:49:35 +02:00
|
|
|
|
try
|
2019-05-09 20:53:52 +02:00
|
|
|
|
JsonArray := TJDOJsonArray.Create;
|
2019-04-16 23:12:19 +02:00
|
|
|
|
try
|
2019-05-09 20:53:52 +02:00
|
|
|
|
BookMark := ADataSet.BookMark;
|
|
|
|
|
lNameCase := GetNameCase(ADataSet, ANameCase);
|
|
|
|
|
ADataSet.First;
|
|
|
|
|
while not ADataSet.Eof do
|
|
|
|
|
begin
|
|
|
|
|
LJObj := JsonArray.AddObject;
|
|
|
|
|
DataSetToJsonObject(ADataSet, LJObj, lNameCase, AIgnoredFields, lDataSetFields);
|
|
|
|
|
if Assigned(ASerializationAction) then
|
2019-03-10 16:29:18 +01:00
|
|
|
|
begin
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lLinks.Clear;
|
|
|
|
|
ASerializationAction(ADataSet, lLinks);
|
|
|
|
|
TJDOLinks(lLinks).FillJSONArray(LJObj.A[TMVCConstants.HATEOAS_PROP_NAME]);
|
2019-03-10 16:29:18 +01:00
|
|
|
|
end;
|
2019-05-09 20:53:52 +02:00
|
|
|
|
ADataSet.Next;
|
2019-03-10 16:29:18 +01:00
|
|
|
|
end;
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := JsonArray.ToJSON(True);
|
2019-03-10 16:29:18 +01:00
|
|
|
|
finally
|
2019-05-09 20:53:52 +02:00
|
|
|
|
JsonArray.Free;
|
|
|
|
|
if ADataSet.BookmarkValid(BookMark) then
|
|
|
|
|
ADataSet.GotoBookmark(BookMark);
|
|
|
|
|
ADataSet.FreeBookmark(BookMark);
|
2017-03-29 14:49:35 +02:00
|
|
|
|
end;
|
|
|
|
|
finally
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lDataSetFields.Free;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
end;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2018-07-16 12:34:07 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.SerializeDataSetRecord(const ADataSet: TDataSet;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
const AIgnoredFields: TMVCIgnoredList = []; const ANameCase: TMVCNameCase = ncAsIs;
|
2019-03-10 16:29:18 +01:00
|
|
|
|
const ASerializationAction: TMVCDatasetSerializationAction = nil): string;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JsonObject: TJDOJsonObject;
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lDataSetFields: TMVCDataSetFields;
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lLinks: IMVCLinks;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := EmptyStr;
|
2019-05-19 11:06:03 +02:00
|
|
|
|
if (not Assigned(ADataSet)) or ADataSet.IsEmpty then
|
|
|
|
|
Exit('null');
|
|
|
|
|
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lDataSetFields := GetDataSetFields(ADataSet, AIgnoredFields, GetNameCase(ADataSet, ANameCase));
|
2017-03-29 14:49:35 +02:00
|
|
|
|
try
|
2019-04-16 23:12:19 +02:00
|
|
|
|
JsonObject := TJDOJsonObject.Create;
|
|
|
|
|
try
|
2019-10-24 15:34:40 +02:00
|
|
|
|
DataSetToJsonObject(ADataSet, JsonObject, GetNameCase(ADataSet, ANameCase), AIgnoredFields, lDataSetFields);
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lLinks := TJDOLinks.Create;
|
|
|
|
|
if Assigned(ASerializationAction) then
|
|
|
|
|
begin
|
|
|
|
|
ASerializationAction(ADataSet, lLinks);
|
|
|
|
|
TJDOLinks(lLinks).FillJSONArray(JsonObject.A[TMVCConstants.HATEOAS_PROP_NAME]);
|
|
|
|
|
end;
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := JsonObject.ToJSON(True);
|
2019-04-16 23:12:19 +02:00
|
|
|
|
finally
|
|
|
|
|
JsonObject.Free;
|
|
|
|
|
end;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
finally
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lDataSetFields.Free;
|
2017-03-29 14:49:35 +02:00
|
|
|
|
end;
|
2017-03-13 20:52:11 +01:00
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.SerializeObject(const AObject: TObject; const AType: TMVCSerializationType;
|
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): string;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
var
|
2019-05-09 20:53:52 +02:00
|
|
|
|
LJObj: TJDOJsonObject;
|
|
|
|
|
lObjType: TRttiType;
|
|
|
|
|
lDict: IMVCLinks;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := EmptyStr;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
if not Assigned(AObject) then
|
2017-05-18 00:02:22 +02:00
|
|
|
|
Exit('null');
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
if AObject is TJsonBaseObject then
|
2017-05-18 00:02:22 +02:00
|
|
|
|
Exit(TJsonBaseObject(AObject).ToJSON(True));
|
|
|
|
|
|
2018-07-16 12:34:07 +02:00
|
|
|
|
if AObject is TDataSet then
|
|
|
|
|
Exit(self.SerializeDataSet(TDataSet(AObject)));
|
|
|
|
|
|
2019-01-08 12:48:27 +01:00
|
|
|
|
if AObject is System.JSON.TJsonValue then
|
|
|
|
|
Exit(System.JSON.TJsonValue(AObject).ToJSON);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lObjType := GetRttiContext.GetType(AObject.ClassType);
|
2018-12-12 11:00:41 +01:00
|
|
|
|
|
2019-05-09 20:53:52 +02:00
|
|
|
|
if GetTypeSerializers.ContainsKey(lObjType.Handle) then
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2019-05-09 20:53:52 +02:00
|
|
|
|
GetTypeSerializers.Items[lObjType.Handle].SerializeRoot(AObject, TObject(LJObj), []);
|
2018-10-30 13:53:01 +01:00
|
|
|
|
try
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := LJObj.ToJSON(True);
|
2018-10-30 13:53:01 +01:00
|
|
|
|
finally
|
2019-05-09 20:53:52 +02:00
|
|
|
|
LJObj.Free;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-05-09 20:53:52 +02:00
|
|
|
|
LJObj := TJDOJsonObject.Create;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
try
|
2019-03-08 09:33:41 +01:00
|
|
|
|
if Assigned(ASerializationAction) then
|
|
|
|
|
begin
|
2019-05-09 20:53:52 +02:00
|
|
|
|
lDict := TJDOLinks.Create;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
InternalObjectToJsonObject(AObject, LJObj, GetSerializationType(AObject, AType), AIgnoredAttributes,
|
2019-05-09 20:53:52 +02:00
|
|
|
|
ASerializationAction, lDict, fStringDictionarySerializer);
|
2019-03-08 09:33:41 +01:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
InternalObjectToJsonObject(AObject, LJObj, GetSerializationType(AObject, AType), AIgnoredAttributes, nil,
|
2019-03-08 09:33:41 +01:00
|
|
|
|
nil, nil);
|
|
|
|
|
end;
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := LJObj.ToJSON(True);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
finally
|
2019-05-09 20:53:52 +02:00
|
|
|
|
LJObj.Free;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-09-18 01:14:54 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.SerializeObject(const AObject: IInterface; const AType: TMVCSerializationType;
|
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): string;
|
|
|
|
|
var
|
|
|
|
|
LIgnoredAttrs: TList<string>;
|
|
|
|
|
begin
|
|
|
|
|
if not Assigned(AObject) then
|
|
|
|
|
Exit('null');
|
|
|
|
|
|
|
|
|
|
LIgnoredAttrs := TList<string>.Create;
|
|
|
|
|
try
|
|
|
|
|
LIgnoredAttrs.AddRange(AIgnoredAttributes);
|
2019-10-24 15:34:40 +02:00
|
|
|
|
// if Assigned(GetRttiContext.GetType(TObject(AObject).ClassType).GetProperty('RefCount')) then
|
|
|
|
|
// LIgnoredAttrs.Add('RefCount');
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := SerializeObject(TObject(AObject), AType, TMVCIgnoredList(LIgnoredAttrs.ToArray), ASerializationAction);
|
2019-09-18 01:14:54 +02:00
|
|
|
|
finally
|
|
|
|
|
LIgnoredAttrs.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.SerializeObjectToJSON(const AObject: TObject; const AType: TMVCSerializationType;
|
|
|
|
|
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction): TJDOJsonObject;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JsonObject: TJDOJsonObject;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
ObjType: TRttiType;
|
|
|
|
|
begin
|
|
|
|
|
if not Assigned(AObject) then
|
2019-01-08 12:48:27 +01:00
|
|
|
|
Exit(TJDOJsonObject.Create);
|
2018-12-12 11:00:41 +01:00
|
|
|
|
|
|
|
|
|
if AObject is TJsonBaseObject then
|
2019-01-08 12:48:27 +01:00
|
|
|
|
Exit(TJsonBaseObject(AObject).Clone as TJDOJsonObject);
|
2018-12-12 11:00:41 +01:00
|
|
|
|
|
|
|
|
|
if AObject is TDataSet then
|
|
|
|
|
begin
|
|
|
|
|
raise Exception.Create('Not supported yet');
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if AObject is TJsonValue then
|
2019-04-03 09:42:15 +02:00
|
|
|
|
begin
|
2019-01-08 12:48:27 +01:00
|
|
|
|
Exit(TJDOJsonObject.Parse(TJsonValue(AObject).ToJSON) as TJDOJsonObject);
|
2019-04-03 09:42:15 +02:00
|
|
|
|
end;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
|
|
|
|
|
ObjType := GetRttiContext.GetType(AObject.ClassType);
|
|
|
|
|
|
|
|
|
|
if GetTypeSerializers.ContainsKey(ObjType.Handle) then
|
|
|
|
|
begin
|
|
|
|
|
GetTypeSerializers.Items[ObjType.Handle].SerializeRoot(AObject, TObject(JsonObject), []);
|
|
|
|
|
try
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := JsonObject;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
except
|
|
|
|
|
JsonObject.Free;
|
|
|
|
|
raise;
|
|
|
|
|
end;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := TJDOJsonObject.Create;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
try
|
2020-02-03 10:51:40 +01:00
|
|
|
|
ObjectToJsonObject(AObject, Result, GetSerializationType(AObject, AType), AIgnoredAttributes);
|
2018-12-12 11:00:41 +01:00
|
|
|
|
except
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result.Free;
|
2018-12-12 11:00:41 +01:00
|
|
|
|
raise;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2020-02-03 10:51:40 +01:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.TryNullableToJSON(const AValue: TValue; const AJsonObject: TJDOJsonObject;
|
|
|
|
|
const AName: String): Boolean;
|
|
|
|
|
begin
|
|
|
|
|
Result := False;
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableString)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableString>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.S[AName] := AValue.AsType<NullableString>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableInt32)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableInt32>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.I[AName] := AValue.AsType<NullableInt32>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableInt64)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableInt64>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.L[AName] := AValue.AsType<NullableInt64>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableInt16)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableInt16>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.I[AName] := AValue.AsType<NullableInt16>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableTDate)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableTDate>().HasValue then
|
|
|
|
|
begin
|
2020-02-03 12:11:42 +01:00
|
|
|
|
AJsonObject.S[AName] := DateToISODate(AValue.AsType<NullableTDate>().Value);
|
2020-02-03 10:51:40 +01:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableTDateTime)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableTDateTime>().HasValue then
|
|
|
|
|
begin
|
2020-02-03 12:11:42 +01:00
|
|
|
|
AJsonObject.S[AName] := DateTimeToISOTimeStamp(AValue.AsType<NullableTDateTime>().Value);
|
2020-02-03 10:51:40 +01:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableTTime)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableTTime>().HasValue then
|
|
|
|
|
begin
|
2020-02-03 12:11:42 +01:00
|
|
|
|
AJsonObject.S[AName] := TimeToISOTime(AValue.AsType<NullableTTime>().Value);
|
2020-02-03 10:51:40 +01:00
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableBoolean)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableBoolean>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.B[AName] := AValue.AsType<NullableBoolean>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableCurrency)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableCurrency>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.F[AName] := AValue.AsType<NullableCurrency>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableSingle)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableSingle>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.F[AName] := AValue.AsType<NullableSingle>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableDouble)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableDouble>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.F[AName] := AValue.AsType<NullableDouble>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
if (AValue.TypeInfo = System.TypeInfo(NullableExtended)) then
|
|
|
|
|
begin
|
|
|
|
|
if AValue.AsType<NullableExtended>().HasValue then
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.F[AName] := AValue.AsType<NullableExtended>().Value;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
AJsonObject.Values[AName] := nil;
|
|
|
|
|
end;
|
|
|
|
|
Exit(True);
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TMVCJsonDataObjectsSerializer.DeserializeObject(const ASerializedObject: string; const AObject: TObject;
|
2018-07-16 12:34:07 +02:00
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JsonObject: TJDOJsonObject;
|
2019-03-05 20:55:37 +01:00
|
|
|
|
JsonBase: TJsonBaseObject;
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
|
|
|
|
if (ASerializedObject = EmptyStr) then
|
2018-10-31 01:07:23 +01:00
|
|
|
|
raise EMVCException.Create(http_status.BadRequest, 'Invalid body');
|
2017-03-01 21:40:57 +01:00
|
|
|
|
|
|
|
|
|
if not Assigned(AObject) then
|
|
|
|
|
Exit;
|
|
|
|
|
|
|
|
|
|
try
|
2019-03-05 20:55:37 +01:00
|
|
|
|
JsonBase := TJDOJsonObject.Parse(ASerializedObject);
|
|
|
|
|
if not(JsonBase is TJDOJsonObject) then
|
|
|
|
|
begin
|
|
|
|
|
raise EMVCSerializationException.CreateFmt('Invalid JSON. Expected %s got %s',
|
|
|
|
|
[TJDOJsonObject.ClassName, JsonBase.ClassName]);
|
|
|
|
|
end;
|
|
|
|
|
JsonObject := TJDOJsonObject(JsonBase);
|
2018-10-31 01:07:23 +01:00
|
|
|
|
except
|
|
|
|
|
on E: EJsonParserException do
|
2017-03-01 21:40:57 +01:00
|
|
|
|
begin
|
2018-10-31 01:07:23 +01:00
|
|
|
|
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
|
2019-10-24 15:34:40 +02:00
|
|
|
|
JsonObjectToObject(JsonObject, AObject, GetSerializationType(AObject, AType), AIgnoredAttributes);
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end;
|
|
|
|
|
finally
|
|
|
|
|
JsonObject.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
function TMVCJsonDataObjectsSerializer.GetDataSetFields(const ADataSet: TDataSet;
|
|
|
|
|
const AIgnoredFields: TMVCIgnoredList = []; const ANameCase: TMVCNameCase = ncAsIs): TMVCDataSetFields;
|
2019-04-16 23:12:19 +02:00
|
|
|
|
var
|
|
|
|
|
I: Integer;
|
|
|
|
|
lField: TMVCDataSetField;
|
|
|
|
|
begin
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := TMVCDataSetFields.Create;
|
2019-04-16 23:12:19 +02:00
|
|
|
|
for I := 0 to ADataSet.Fields.Count - 1 do
|
|
|
|
|
Begin
|
2019-10-24 15:34:40 +02:00
|
|
|
|
lField.FieldName := GetNameAs(ADataSet.Owner, ADataSet.Fields[I].Name, ADataSet.Fields[I].FieldName);
|
2019-04-16 23:12:19 +02:00
|
|
|
|
lField.DataType := ADataSet.Fields[I].DataType;
|
|
|
|
|
lField.I := I;
|
|
|
|
|
case ANameCase of
|
|
|
|
|
ncUpperCase:
|
|
|
|
|
lField.FieldName := UpperCase(ADataSet.Fields[I].FieldName);
|
|
|
|
|
ncLowerCase:
|
|
|
|
|
lField.FieldName := LowerCase(ADataSet.Fields[I].FieldName);
|
|
|
|
|
end;
|
|
|
|
|
if (not IsIgnoredAttribute(AIgnoredFields, lField.FieldName)) and
|
|
|
|
|
(not IsIgnoredComponent(ADataSet.Owner, ADataSet.Fields[I].Name)) then
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result.Add(lField);
|
2019-04-16 23:12:19 +02:00
|
|
|
|
End;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-10-24 15:34:40 +02:00
|
|
|
|
procedure TValueToJsonElement(const Value: TValue; const JSON: TJDOJsonObject; const KeyName: string);
|
2018-12-12 14:48:35 +01:00
|
|
|
|
var
|
|
|
|
|
lSer: TMVCJsonDataObjectsSerializer;
|
|
|
|
|
lMVCList: IMVCList;
|
2019-01-08 12:48:27 +01:00
|
|
|
|
lOrdinalValue: Int64;
|
|
|
|
|
lValueAsObj: TObject;
|
|
|
|
|
lValueAsObjQualifClassName: string;
|
2018-12-12 14:48:35 +01:00
|
|
|
|
begin
|
2019-05-16 00:16:55 +02:00
|
|
|
|
if Value.IsEmpty then
|
|
|
|
|
begin
|
|
|
|
|
JSON.Values[KeyName] := nil;
|
|
|
|
|
Exit;
|
|
|
|
|
end;
|
|
|
|
|
|
2018-12-12 14:48:35 +01:00
|
|
|
|
case Value.Kind of
|
|
|
|
|
tkInteger:
|
|
|
|
|
begin
|
|
|
|
|
JSON.I[KeyName] := Value.AsInteger;
|
|
|
|
|
end;
|
|
|
|
|
tkFloat:
|
|
|
|
|
begin
|
2019-03-05 20:55:37 +01:00
|
|
|
|
{$IFDEF NEXTGEN}
|
2019-02-19 13:04:53 +01:00
|
|
|
|
if PChar(Pointer(Value.TypeInfo.Name)) = 'TDate' then
|
2019-03-05 20:55:37 +01:00
|
|
|
|
{$ELSE}
|
2018-12-12 14:48:35 +01:00
|
|
|
|
if Value.TypeInfo.Name = 'TDate' then
|
2019-03-05 20:55:37 +01:00
|
|
|
|
{$ENDIF}
|
2018-12-12 14:48:35 +01:00
|
|
|
|
begin
|
|
|
|
|
JSON.DUtc[KeyName] := Value.AsExtended;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
JSON.F[KeyName] := Value.AsExtended;
|
|
|
|
|
end;
|
2019-01-08 12:48:27 +01:00
|
|
|
|
end;
|
2018-12-12 14:48:35 +01:00
|
|
|
|
tkString, tkUString, tkWChar, tkLString, tkWString:
|
|
|
|
|
begin
|
|
|
|
|
JSON.S[KeyName] := Value.AsString;
|
|
|
|
|
end;
|
|
|
|
|
tkInt64:
|
|
|
|
|
begin
|
|
|
|
|
JSON.I[KeyName] := Value.AsInt64;
|
|
|
|
|
end;
|
2019-01-08 12:48:27 +01:00
|
|
|
|
tkEnumeration:
|
|
|
|
|
begin
|
|
|
|
|
Value.TryAsOrdinal(lOrdinalValue);
|
|
|
|
|
JSON.I[KeyName] := lOrdinalValue;
|
|
|
|
|
end;
|
2019-09-18 13:30:50 +02:00
|
|
|
|
tkClass, tkInterface:
|
2018-12-12 14:48:35 +01:00
|
|
|
|
begin
|
2019-09-18 13:30:50 +02:00
|
|
|
|
if Value.Kind = tkInterface then
|
|
|
|
|
lValueAsObj := TObject(Value.AsInterface)
|
|
|
|
|
else
|
|
|
|
|
lValueAsObj := Value.AsObject;
|
2019-01-08 12:48:27 +01:00
|
|
|
|
lValueAsObjQualifClassName := lValueAsObj.QualifiedClassName.ToLower;
|
|
|
|
|
if (lValueAsObj is TJDOJsonObject) or (lValueAsObj is TJsonObject)
|
|
|
|
|
{$IFDEF RIOORBETTER} or
|
2019-03-10 16:29:18 +01:00
|
|
|
|
{ this is for a bug in delphi103rio }
|
|
|
|
|
(lValueAsObjQualifClassName = 'jsondataobjects.tjsonobject') or
|
|
|
|
|
{ this is for a bug in delphi103rio }
|
|
|
|
|
(lValueAsObj.QualifiedClassName = 'jsondataobjects.tjdojsonobject')
|
2019-01-08 12:48:27 +01:00
|
|
|
|
{$ENDIF}
|
|
|
|
|
then
|
2018-12-12 14:48:35 +01:00
|
|
|
|
begin
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JSON.O[KeyName] := TJDOJsonObject.Create;
|
|
|
|
|
JSON.O[KeyName].Assign(TJDOJsonObject(Value.AsObject));
|
2018-12-12 14:48:35 +01:00
|
|
|
|
end
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if (lValueAsObj is TJDOJsonArray) or (lValueAsObj is TJsonArray)
|
2019-01-08 12:48:27 +01:00
|
|
|
|
{$IFDEF RIOORBETTER} or
|
2019-05-16 00:16:55 +02:00
|
|
|
|
{ this is for a bug in delphi103rio }
|
|
|
|
|
(lValueAsObj.QualifiedClassName = 'jsondataobjects.tjsonarray') or
|
|
|
|
|
{ this is for a bug in delphi103rio }
|
|
|
|
|
(lValueAsObj.QualifiedClassName = 'jsondataobjects.tjdojsonarray')
|
2019-01-08 12:48:27 +01:00
|
|
|
|
{$ENDIF}
|
2019-05-16 00:16:55 +02:00
|
|
|
|
then
|
|
|
|
|
begin
|
|
|
|
|
JSON.A[KeyName] := TJDOJsonArray.Create;
|
|
|
|
|
JSON.A[KeyName].Assign(TJDOJsonArray(Value.AsObject));
|
|
|
|
|
end
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if lValueAsObj is TDataSet then
|
2019-05-16 00:16:55 +02:00
|
|
|
|
begin
|
|
|
|
|
lSer := TMVCJsonDataObjectsSerializer.Create;
|
|
|
|
|
try
|
2019-01-08 12:48:27 +01:00
|
|
|
|
JSON.A[KeyName] := TJDOJsonArray.Create;
|
2019-10-24 15:34:40 +02:00
|
|
|
|
lSer.DataSetToJsonArray(TDataSet(lValueAsObj), JSON.A[KeyName], TMVCNameCase.ncLowerCase, []);
|
2019-05-16 00:16:55 +02:00
|
|
|
|
finally
|
|
|
|
|
lSer.Free;
|
|
|
|
|
end;
|
|
|
|
|
end
|
2019-09-18 13:30:50 +02:00
|
|
|
|
else if TDuckTypedList.CanBeWrappedAsList(lValueAsObj, lMVCList) then
|
2019-05-16 00:16:55 +02:00
|
|
|
|
begin
|
|
|
|
|
lSer := TMVCJsonDataObjectsSerializer.Create;
|
|
|
|
|
try
|
|
|
|
|
JSON.A[KeyName] := TJDOJsonArray.Create;
|
|
|
|
|
lSer.ListToJsonArray(lMVCList, JSON.A[KeyName], TMVCSerializationType.stDefault, nil);
|
|
|
|
|
finally
|
|
|
|
|
lSer.Free;
|
|
|
|
|
end;
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
lSer := TMVCJsonDataObjectsSerializer.Create;
|
|
|
|
|
try
|
2019-10-24 15:34:40 +02:00
|
|
|
|
JSON.O[KeyName] := lSer.SerializeObjectToJSON(lValueAsObj, TMVCSerializationType.stProperties, [], nil);
|
2019-05-16 00:16:55 +02:00
|
|
|
|
finally
|
|
|
|
|
lSer.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
2018-12-12 14:48:35 +01:00
|
|
|
|
end;
|
|
|
|
|
else
|
|
|
|
|
raise EMVCException.Create('Invalid type');
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-09-30 00:05:46 +02:00
|
|
|
|
function StrToJSONObject(const AValue: string): TJDOJsonObject;
|
2018-12-12 14:48:35 +01:00
|
|
|
|
var
|
2019-01-08 12:48:27 +01:00
|
|
|
|
lJSON: TJDOJsonObject;
|
2018-12-12 14:48:35 +01:00
|
|
|
|
begin
|
|
|
|
|
lJSON := nil;
|
|
|
|
|
try
|
2019-01-08 12:48:27 +01:00
|
|
|
|
lJSON := TJDOJsonObject.Parse(AValue) as TJDOJsonObject;
|
2020-02-03 10:51:40 +01:00
|
|
|
|
Result := lJSON;
|
2018-12-12 14:48:35 +01:00
|
|
|
|
except
|
|
|
|
|
on E: Exception do
|
|
|
|
|
begin
|
|
|
|
|
lJSON.Free;
|
|
|
|
|
raise EMVCDeserializationException.Create('Invalid JSON');
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-01-08 12:48:27 +01:00
|
|
|
|
procedure JsonObjectToObject(const AJsonObject: TJDOJsonObject; const AObject: TObject;
|
|
|
|
|
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList);
|
2018-12-17 00:39:29 +01:00
|
|
|
|
var
|
|
|
|
|
lSer: TMVCJsonDataObjectsSerializer;
|
|
|
|
|
begin
|
2019-01-08 12:48:27 +01:00
|
|
|
|
lSer := TMVCJsonDataObjectsSerializer.Create;
|
2018-12-17 00:39:29 +01:00
|
|
|
|
try
|
|
|
|
|
lSer.JsonObjectToObject(AJsonObject, AObject, AType, AIgnoredAttributes);
|
|
|
|
|
finally
|
|
|
|
|
lSer.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2019-05-09 20:53:52 +02:00
|
|
|
|
procedure MVCStringDictionaryListToJSONArray(const aStringDictionaryList: TMVCStringDictionaryList;
|
|
|
|
|
const AJsonArray: TJsonArray);
|
|
|
|
|
var
|
|
|
|
|
lStringDictionary: TMVCStringDictionary;
|
|
|
|
|
begin
|
|
|
|
|
if aStringDictionaryList = nil then
|
|
|
|
|
Exit;
|
|
|
|
|
for lStringDictionary in aStringDictionaryList do
|
|
|
|
|
begin
|
|
|
|
|
TMVCStringDictionarySerializer.Serialize(lStringDictionary, AJsonArray.AddObject);
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
|
|
|
|
{ TJDOLinks }
|
|
|
|
|
|
|
|
|
|
procedure TJDOLinks.FillJSONArray(const AJsonArray: TJsonArray);
|
|
|
|
|
begin
|
|
|
|
|
MVCStringDictionaryListToJSONArray(LinksData, AJsonArray);
|
|
|
|
|
end;
|
|
|
|
|
|
2019-11-06 15:08:29 +01:00
|
|
|
|
{ TJSONObjectHelper }
|
|
|
|
|
|
|
|
|
|
procedure TJSONObjectHelper.LoadFromString(const Value: String; Encoding: TEncoding; Utf8WithoutBOM: Boolean);
|
|
|
|
|
var
|
|
|
|
|
lSS: TStringStream;
|
|
|
|
|
begin
|
|
|
|
|
if Assigned(Encoding) then
|
|
|
|
|
begin
|
|
|
|
|
lSS := TStringStream.Create(Value, Encoding);
|
|
|
|
|
end
|
|
|
|
|
else
|
|
|
|
|
begin
|
|
|
|
|
lSS := TStringStream.Create(Value);
|
|
|
|
|
end;
|
|
|
|
|
try
|
|
|
|
|
lSS.Position := 0;
|
|
|
|
|
LoadFromStream(lSS, Encoding, Utf8WithoutBOM);
|
|
|
|
|
finally
|
|
|
|
|
lSS.Free;
|
|
|
|
|
end;
|
|
|
|
|
end;
|
|
|
|
|
|
2017-03-01 21:40:57 +01:00
|
|
|
|
end.
|