2024-02-12 18:11:48 +01:00
// ***************************************************************************
2017-03-01 21:40:57 +01:00
//
// Delphi MVC Framework
//
2024-01-02 17:04:27 +01:00
// Copyright (c) 2010-2024 Daniele Teti and the DMVCFramework Team
2017-03-01 21:40:57 +01:00
//
// https://github.com/danieleteti/delphimvcframework
//
2024-01-02 17:04:27 +01:00
// Collaborators with this file: Ezequiel Juliano M<> ller (ezequieljuliano@gmail.com)
2017-03-01 21:40:57 +01:00
//
// ***************************************************************************
//
// 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}
2020-04-20 17:56:17 +02:00
{$WARN SYMBOL_DEPRECATED OFF}
2020-04-21 17:04:04 +02:00
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. DuckTyping,
2020-04-20 17:56:17 +02:00
MVCFramework. Serializer. Commons,
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 ;
TMVCDataSetFields = TList< TMVCDataSetField> ;
2019-11-06 15:08:29 +01:00
TJSONObjectHelper = class helper for TJsonObject
public
2020-04-09 17:01:33 +02:00
procedure LoadFromString( const Value: string ; Encoding: TEncoding = nil ; Utf8WithoutBOM: Boolean = True ) ;
2019-11-06 15:08:29 +01:00
end ;
2021-08-19 17:58:19 +02:00
TMVCJsonDataObjectsSerializer = class( TMVCAbstractSerializer, IMVCSerializer, IMVCJSONSerializer)
2019-03-08 09:33:41 +01:00
private
fStringDictionarySerializer: IMVCTypeSerializer;
2021-01-27 20:25:35 +01:00
function TryMapNullableFloat( var Value: TValue; const JSONDataObject: TJsonObject;
const AttribName: string ) : Boolean ;
2022-08-12 10:50:46 +02:00
type
TFieldMetaInfo = record
NameAs: String ;
Ignored: Boolean ;
end ;
TSerializationMetaInfo = record
FieldsMetaInfo: TArray< TFieldMetaInfo> ;
IgnoredFields: TMVCIgnoredList;
NameCase: TMVCNameCase;
class function CreateFieldsMetaInfo(
const ADataSet: TDataSet;
const ANameCase: TMVCNameCase;
const AIgnoredFields: TMVCIgnoredList) : TSerializationMetaInfo; static ;
end ;
2019-09-30 00:05:46 +02:00
public
2022-08-10 17:57:59 +02:00
procedure ParseStringAsTValueUsingMetadata(
const AStringValue: String ;
const DestinationTypeInfo: PTypeInfo;
const ExceptionHintString: String ;
const AAttributes: TArray< TCustomAttribute> ;
var AValue: TValue) ;
2022-08-01 19:11:42 +02:00
function JSONObjectToRecord< T: record > ( const JSONObject: TJsonObject) : T; overload ;
function StrToRecord< T: record > ( const AJSONString: String ) : T;
procedure JSONObjectToNestedRecordField( const JSONObject: TJsonObject; RecordFieldRTTIType: TRttiField;
const TypeOffset: Integer ; var Buffer: PByte ) ;
procedure JSONObjectToNestedRecordFieldStatic( const JSONObject: TJsonObject; RecordFieldRTTIType: TRttiField;
const TypeOffset: Integer ; var Buffer: PByte ) ;
procedure JSONObjectPropertyToTValueForRecord( AJSONObject: TJsonObject; const APropertyName: String ;
const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList; var AValue: TValue;
const ACustomAttributes: TArray< TCustomAttribute> ; const ARTTIField: TRttiField) ;
2020-05-19 00:49:34 +02:00
function GetDataSetFields( const ADataSet: TDataSet; const AIgnoredFields: TMVCIgnoredList;
2019-04-16 23:12:19 +02:00
const ANameCase: TMVCNameCase = ncAsIs) : TMVCDataSetFields;
2022-08-01 19:11:42 +02:00
procedure ObjectToJsonObject( const AObject: TObject; const AJSONObject: TJDOJsonObject;
2018-07-16 12:34:07 +02:00
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList) ;
2022-08-01 19:11:42 +02:00
procedure InternalObjectToJsonObject( const AObject: TObject; const AJSONObject: TJDOJsonObject;
2019-10-24 15:34:40 +02:00
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) ;
2022-07-05 13:20:09 +02:00
procedure InternalRecordToJsonObject( const ARecord: Pointer ; const ARecordTypeInfo: PTypeInfo;
2022-08-01 19:11:42 +02:00
const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
2022-07-05 12:26:35 +02:00
const ASerializationAction: TMVCSerializationAction; const Links: IMVCLinks;
const Serializer: IMVCTypeSerializer) ;
2022-08-01 19:11:42 +02:00
procedure InternalTValueToJsonObject( const AValue: TValue; const AJSONObject: TJDOJsonObject;
2022-05-25 15:13:49 +02:00
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
const ASerializationAction: TMVCSerializationAction; const Links: IMVCLinks;
const Serializer: IMVCTypeSerializer) ;
2021-01-27 20:25:35 +01:00
function ConvertObjectToJsonValue( const AObject: TObject; const AType: TMVCSerializationType;
2022-08-28 13:06:16 +02:00
const AIgnoredFields: TMVCIgnoredList;
2020-09-23 23:33:30 +02:00
const ADataSetSerializationCallback: TMVCDataSetFieldSerializationAction;
2021-01-27 20:25:35 +01:00
const ASerializationAction: TMVCSerializationAction; out AJsonDataType: TJsonDataType) : TJsonBaseObject;
2022-08-01 19:11:42 +02:00
function ConvertRecordToJsonValue( const ARecord: Pointer ; const ARecordTypeInfo: PTypeInfo;
2022-07-05 13:20:09 +02:00
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
const ADataSetSerializationCallback: TMVCDataSetFieldSerializationAction;
const ASerializationAction: TMVCSerializationAction; out AJsonDataType: TJsonDataType) : TJsonBaseObject;
2020-09-11 13:37:45 +02:00
procedure AddTValueToJsonArray( const Value: TValue; const JSON: TJDOJsonArray) ;
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 ) ;
2022-08-01 19:11:42 +02:00
procedure TValueToJSONObjectProperty( 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> ) ;
2022-08-01 19:11:42 +02:00
function TryNullableToJSON( const AValue: TValue; const AJSONObject: TJDOJsonObject; const AName: string ;
2022-06-24 19:50:23 +02:00
const ACustomAttributes: TArray< TCustomAttribute> ) : Boolean ;
2022-08-01 19:11:42 +02:00
procedure JsonObjectToObject( const AJSONObject: TJDOJsonObject; const AObject: TObject;
2018-07-16 12:34:07 +02:00
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList) ;
2022-07-05 16:18:03 +02:00
procedure JSONObjectToRecord( const JSONObject: TJsonObject; RTTIType: TRttiRecordType; out Buffer: PByte ) ; overload ;
2022-08-01 19:11:42 +02:00
procedure JSONObjectToRecordStatic( const JSONObject: TJsonObject; RTTIType: TRttiRecordType; var Buffer: PByte ) ;
procedure JSONObjectPropertyToTValue( AJSONObject: TJsonObject; const APropertyName: String ;
const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList; var ChildObject: TObject; var AValue: TValue;
2022-04-05 17:17:35 +02:00
const ACustomAttributes: TArray< TCustomAttribute> ) ;
2021-08-17 15:10:58 +02:00
procedure JsonDataValueToAttribute( const AObject: TObject; const ARttiMember: TRttiMember;
2022-08-01 19:11:42 +02:00
const AJSONObject: TJDOJsonObject; const AName: string ; var AValue: TValue; 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) ;
2022-08-01 19:11:42 +02: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) ;
2022-08-01 19:11:42 +02:00
procedure JsonObjectToDataSet( const AJSONObject: TJDOJsonObject; const ADataSet: TDataSet;
2022-08-12 10:50:46 +02:00
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase) ; overload ;
procedure JsonObjectToDataSet( const AJSONObject: TJDOJsonObject; const ADataSet: TDataSet;
const SerializationMetaInfo: TSerializationMetaInfo) ; overload ;
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) ;
2024-04-29 12:50:25 +02:00
function JsonArrayToArray( const AJsonArray: TJDOJsonArray; const ATypeInfo: PTypeInfo) : 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
2022-08-01 19:11:42 +02:00
function SerializeRecord( const ARecord: Pointer ; const ARecordTypeInfo: PTypeInfo;
const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = nil ;
const ASerializationAction: TMVCSerializationAction = nil ) : string ; overload ;
2022-07-05 12:26:35 +02:00
2023-03-14 08:56:00 +01:00
function SerializeArrayOfRecord(
var ATValueContainingAnArray: TValue;
const AType: TMVCSerializationType = stDefault;
const AIgnoredAttributes: TMVCIgnoredList = nil ;
const ASerializationAction: TMVCSerializationAction = nil
) : string ; overload ;
2022-07-05 13:20:09 +02:00
procedure RecordToJsonObject( const ARecord: Pointer ; const ARecordTypeInfo: PTypeInfo;
2022-08-01 19:11:42 +02:00
const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList) ;
2022-07-05 12:26:35 +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
2021-03-03 23:16:55 +01:00
function SerializeDataSet( const ADataSet: TDataSet; const AIgnoredFields: TMVCIgnoredList = [ ] ;
2019-10-24 15:34:40 +02:00
const ANameCase: TMVCNameCase = ncAsIs; const ASerializationAction: TMVCDatasetSerializationAction = nil ) : string ;
2018-07-16 12:34:07 +02:00
2021-01-27 20:25:35 +01:00
function SerializeDataSetRecord( const DataSet: TDataSet; const IgnoredFields: TMVCIgnoredList;
const NameCase: TMVCNameCase = ncAsIs; const SerializationAction: TMVCDatasetSerializationAction = nil ) : string ;
2018-07-16 12:34:07 +02:00
procedure DeserializeObject( const ASerializedObject: string ; const AObject: TObject;
2020-08-13 17:40:02 +02:00
const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = [ ] ;
const ARootNode: string = '' ) ; 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;
2020-09-07 11:28:53 +02:00
const AType: TMVCSerializationType = stDefault; const AIgnoredAttributes: TMVCIgnoredList = [ ] ;
const ARootNode: string = '' ) ; 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;
2020-05-19 00:49:34 +02:00
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase = ncAsIs) ;
2018-07-16 12:34:07 +02:00
2021-01-27 20:25:35 +01:00
procedure InternalSerializeDataSet( const ADataSet: TDataSet; const AJsonArray: TJsonArray;
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase;
2020-04-20 17:56:17 +02:00
const ASerializationAction: TMVCDatasetSerializationAction) ;
2021-01-27 20:25:35 +01:00
procedure InternalSerializeDataSetRecord( const DataSet: TDataSet; const JSONObject: TJsonObject;
2020-04-21 17:04:04 +02:00
const IgnoredFields: TMVCIgnoredList; const NameCase: TMVCNameCase;
const SerializationAction: TMVCDatasetSerializationAction) ;
2019-10-24 15:34:40 +02:00
procedure DeserializeDataSetRecord( const ASerializedDataSetRecord: string ; const ADataSet: TDataSet;
2020-05-19 00:49:34 +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 ;
2020-04-29 18:45:01 +02:00
TJDOLinks = class( TMVCLinks)
public
procedure FillJSONArray( const AJsonArray: TJsonArray) ;
end ;
2022-07-25 15:32:31 +02:00
TJSONUtils = record
2022-07-05 16:51:31 +02:00
private
2022-08-01 19:11:42 +02:00
class function JSONObjectToRecord< T: record > ( const JSONObject: TJsonObject;
const Serializer: TMVCJsonDataObjectsSerializer) : T; overload ; static ; inline ;
2022-07-05 16:51:31 +02:00
public
2022-08-01 19:11:42 +02:00
// records
class function JSONObjectToRecord< T: record > ( const JSONObject: TJsonObject) : T; overload ; static ;
class function JSONArrayToArrayOfRecord< T: record > ( const JSONArray: TJsonArray) : TArray< T> ; overload ; static ;
// objects
class function JsonObjectToObject< T: class , constructor > ( const JSONObject: TJsonObject) : T; overload ; static ;
class function JSONArrayToListOf< T: class , constructor > ( const JSONArray: TJsonArray) : TObjectList< T> ;
overload ; static ;
2022-07-05 16:18:03 +02:00
end ;
2022-07-05 13:20:09 +02:00
procedure TValueToJSONObjectPropertyEx( const Value: TValue; const JSON: TJDOJsonObject; const KeyName: string ) ;
2021-04-06 19:21:53 +02:00
function StrToJSONObject( const AValue: string ; ARaiseExceptionOnError: Boolean = False ) : TJDOJsonObject; inline ;
function StrToJSONArray( const AValue: string ; ARaiseExceptionOnError: Boolean = False ) : TJDOJsonArray; inline ;
2022-08-01 19:11:42 +02:00
procedure JsonObjectToObject( const AJSONObject: TJDOJsonObject; const AObject: TObject;
2020-09-22 15:18:22 +02:00
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList) ; overload ;
2022-08-01 19:11:42 +02:00
procedure JsonObjectToObject( const AJSONObject: TJDOJsonObject; const AObject: TObject) ; overload ;
2020-09-22 15:18:22 +02:00
procedure JsonArrayToList( const AJsonArray: TJDOJsonArray; const AList: IMVCList; const AClazz: TClass;
2019-01-08 12:48:27 +01:00
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList) ;
2018-12-12 14:48:35 +01:00
2020-04-09 17:01:33 +02:00
const
2021-01-27 20:25:35 +01:00
JDO_TYPE_DESC: array [ TJsonDataType. jdtNone .. TJsonDataType. jdtObject] of string = ( 'None' , 'String' , 'Int' , 'Long' ,
'ULong' , 'Float' , 'DateTime' , 'UtcDateTime' , 'Bool' , 'Array' , 'Object' ) ;
2020-04-09 17:01:33 +02: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
2020-08-13 17:40:02 +02:00
function SelectRootNodeOrWholeObject( const RootNode: string ; const JSONObject: TJsonObject) : TJsonObject; inline ;
begin
if RootNode. IsEmpty then
begin
Result : = JSONObject
end
else
begin
Result : = JSONObject. O[ RootNode] ;
end ;
end ;
2020-04-29 18:45:01 +02:00
{ 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;
2020-04-18 23:32:24 +02:00
fObjectDictionarySerializer: TMVCObjectDictionarySerializer;
2017-03-02 12:57:40 +01:00
begin
inherited AfterConstruction;
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) ;
2024-10-24 12:59:26 +02:00
GetTypeSerializers. Add( TypeInfo( TBytesStream) , lStreamSerializer) ;
2019-03-08 09:33:41 +01:00
fStringDictionarySerializer : = TMVCStringDictionarySerializer. Create;
2020-04-18 23:32:24 +02:00
GetTypeSerializers. Add( TypeInfo( TMVCStringDictionary) , fStringDictionarySerializer) ;
2019-06-26 19:31:53 +02:00
GetTypeSerializers. Add( TypeInfo( TGUID) , TMVCGUIDSerializer. Create) ;
2024-10-24 12:59:26 +02:00
2020-04-20 17:56:17 +02:00
fObjectDictionarySerializer : = TMVCObjectDictionarySerializer. Create( self) ;
2020-04-18 23:32:24 +02:00
GetTypeSerializers. Add( TypeInfo( TMVCObjectDictionary) , fObjectDictionarySerializer) ;
2022-08-01 19:11:42 +02:00
GetTypeSerializers. Add( TypeInfo( TMVCListOfString { TList<string> } ) , TMVCListOfStringSerializer. Create) ;
GetTypeSerializers. Add( TypeInfo( TMVCListOfInteger { TList<Integer> } ) , TMVCListOfIntegerSerializer. Create) ;
GetTypeSerializers. Add( TypeInfo( TMVCListOfBoolean { TList<Boolean> } ) , TMVCListOfBooleanSerializer. Create) ;
GetTypeSerializers. Add( TypeInfo( TMVCListOfDouble { TList<Double> } ) , TMVCListOfDoubleSerializer. Create) ;
2017-03-02 12:57:40 +01:00
end ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. TValueToJSONObjectProperty( const AJSONObject: TJDOJsonObject;
const AName: string ; 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;
2017-03-01 21:40:57 +01:00
ChildValue: TValue;
ChildObject, Obj: TObject;
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 ;
2020-09-11 13:01:56 +02:00
lJSONValue: TJsonBaseObject;
lJsonDataType: TJsonDataType;
2021-06-01 15:10:45 +02:00
lTypeInfo: PTypeInfo;
2022-04-05 17:17:35 +02:00
lBuffer: Pointer ;
2022-07-22 19:55:27 +02:00
lCurrentArrayItem: TValue;
2017-03-01 21:40:57 +01:00
begin
2024-06-08 23:05:46 +02:00
// if SameText(AName, 'RefCount') then
// begin
// Exit;
// end;
2019-10-10 20:16:20 +02:00
2017-03-01 21:40:57 +01:00
if AValue. IsEmpty then
begin
2022-11-07 19:22:25 +01:00
if AValue. IsArray then
begin
AJSONObject. A[ AName] : = TJDOJsonArray. Create;
end
else
begin
2023-01-28 23:31:00 +01:00
if MVCSerializeNulls then
begin
AJSONObject[ AName] : = Null;
end ;
2022-11-07 19:22:25 +01:00
end ;
2017-03-01 21:40:57 +01:00
Exit;
end ;
2022-11-07 19:22:25 +01:00
2021-06-01 15:10:45 +02:00
lTypeInfo : = AValue. TypeInfo;
// AValue.TypeInfo does not show the correct TypeInfo of the class instantiated for the object or interface
ChildObject : = nil ;
if AValue. Kind in [ tkClass, tkInterface] then
2017-03-01 21:40:57 +01:00
begin
2021-06-01 15:10:45 +02:00
if not AValue. IsEmpty and ( AValue. Kind = tkInterface) then
ChildObject : = TObject( AValue. AsInterface)
else if AValue. Kind = tkClass then
ChildObject : = AValue. AsObject;
if Assigned( ChildObject) then
lTypeInfo : = ChildObject. ClassInfo;
end ;
if GetTypeSerializers. ContainsKey( lTypeInfo) then
begin
2022-08-01 19:11:42 +02:00
GetTypeSerializers. Items[ lTypeInfo] . SerializeAttribute( AValue, AName, AJSONObject, ACustomAttributes) ;
2017-03-01 21:40:57 +01:00
Exit;
end ;
case AValue. Kind of
tkInteger:
2024-05-10 16:16:47 +02:00
begin
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( ACustomAttributes) then
begin
AJSONObject. S[ AName] : = TMVCSqids. IntToSqid( AValue. AsInteger) ;
end
else
begin
AJSONObject. I[ AName] : = AValue. AsInteger;
end ;
end ;
2017-03-01 21:40:57 +01:00
tkInt64:
2024-05-10 16:16:47 +02:00
begin
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( ACustomAttributes) then
begin
AJSONObject. S[ AName] : = TMVCSqids. IntToSqid( AValue. AsInt64) ;
end
else
begin
AJSONObject. L[ AName] : = AValue. AsInt64;
end ;
end ;
2017-03-01 21:40:57 +01:00
tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = AValue. AsString;
2017-03-01 21:40:57 +01:00
tkFloat:
begin
if ( AValue. TypeInfo = System. TypeInfo( TDate) ) then
begin
if ( AValue. AsExtended = 0 ) then
2022-08-01 19:11:42 +02:00
AJSONObject[ AName] : = Null
2017-03-01 21:40:57 +01:00
else
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = DateToISODate( AValue. AsExtended) ;
2017-03-01 21:40:57 +01:00
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
2022-08-01 19:11:42 +02:00
AJSONObject[ AName] : = Null
2019-05-09 20:53:52 +02:00
else
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = DateTimeToISOTimeStamp( AValue. AsExtended) ;
2019-05-16 00:16:55 +02:00
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
2022-08-01 19:11:42 +02:00
AJSONObject[ AName] : = Null
2019-05-16 00:16:55 +02:00
else
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = TimeToISOTime( AValue. AsExtended) ;
2019-05-16 00:16:55 +02:00
end
else
2024-07-22 14:28:32 +02:00
begin
2022-08-01 19:11:42 +02:00
AJSONObject. F[ AName] : = AValue. AsExtended;
2024-07-22 14:28:32 +02:00
end ;
2017-03-01 21:40:57 +01:00
end ;
tkVariant:
2022-08-01 19:11:42 +02:00
AJSONObject[ AName] : = AValue. AsVariant;
2017-03-01 21:40:57 +01:00
tkEnumeration:
begin
if ( AValue. TypeInfo = System. TypeInfo( Boolean ) ) then
begin
if AValue. AsBoolean then
2022-08-01 19:11:42 +02:00
AJSONObject. B[ AName] : = True
2017-03-01 21:40:57 +01:00
else
2022-08-01 19:11:42 +02:00
AJSONObject. B[ AName] : = False
2017-03-01 21:40:57 +01:00
end
else
2019-08-12 21:48:33 +02:00
begin
LEnumSerType : = estEnumName;
2020-03-12 18:24:20 +01:00
LEnumMappedValues : = nil ;
2021-01-27 20:25:35 +01:00
if TMVCSerializerHelper. AttributeExists< MVCEnumSerializationAttribute> ( ACustomAttributes, LEnumAsAttr) 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) ;
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = LEnumName;
2019-08-12 21:48:33 +02:00
end ;
estEnumOrd:
begin
2022-08-01 19:11:42 +02:00
AJSONObject. I[ AName] : = AValue. AsOrdinal;
2019-08-12 21:48:33 +02:00
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' ) ;
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = LEnumMappedValues[ AValue. AsOrdinal] ;
2020-03-12 18:24:20 +01:00
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
if Assigned( ChildObject) then
begin
2021-01-27 20:25:35 +01:00
lJSONValue : = ConvertObjectToJsonValue( ChildObject, GetSerializationType( ChildObject, AType) , AIgnored, nil ,
nil , lJsonDataType) ;
2020-09-11 13:01:56 +02:00
case lJsonDataType of
jdtArray:
2019-03-08 09:33:41 +01:00
begin
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] : = TJsonArray( lJSONValue) ;
2019-03-08 09:33:41 +01:00
end ;
2020-09-11 13:01:56 +02:00
jdtObject:
begin
2022-08-01 19:11:42 +02:00
AJSONObject. O[ AName] : = TJsonObject( lJSONValue) ;
2020-09-11 13:01:56 +02:00
end
else
2018-07-16 12:34:07 +02:00
begin
2020-09-11 13:01:56 +02:00
lJSONValue. Free;
RaiseSerializationError( 'Invalid JSON Data Type' ) ;
2018-07-16 12:34:07 +02:00
end ;
2017-03-01 21:40:57 +01:00
end ;
end
else
begin
2022-08-01 19:11:42 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsStringAttribute> ( ACustomAttributes) then
AJSONObject. S[ AName] : = EmptyStr
2017-03-01 21:40:57 +01:00
else
2022-08-01 19:11:42 +02:00
AJSONObject[ AName] : = Null;
2017-03-01 21:40:57 +01:00
end ;
end ;
tkRecord:
begin
2020-04-27 16:25:50 +02:00
if AValue. TypeInfo. NameFld. ToString. StartsWith( 'Nullable' ) then
2020-02-03 10:51:40 +01:00
begin
2022-08-01 19:11:42 +02:00
if TryNullableToJSON( AValue, AJSONObject, AName, ACustomAttributes) then
2020-02-03 10:51:40 +01:00
begin
Exit;
end ;
end ;
2017-03-01 21:40:57 +01:00
if ( AValue. TypeInfo = System. TypeInfo( TTimeStamp) ) then
begin
2024-07-22 14:28:32 +02:00
AJSONObject. L[ AName] : = Trunc( TimeStampToMsecs( AValue. AsType< TTimeStamp> ) ) ;
2017-03-01 21:40:57 +01:00
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
2022-08-01 19:11:42 +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
2022-07-23 01:21:52 +02:00
begin
2022-08-01 19:11:42 +02:00
TValueToJSONObjectProperty( AJSONObject, AName, CastedValue, stDefault, [ ] , [ ] )
2022-07-23 01:21:52 +02:00
end
2017-03-01 21:40:57 +01:00
else
2022-07-23 01:21:52 +02:00
begin
2022-08-01 19:11:42 +02:00
RaiseSerializationError
( Format( 'Cannot serialize property or field "%s" of TypeKind tkRecord (TValue with MVCValueAsTypeAttribute)' ,
[ AName] ) ) ;
2022-07-23 01:21:52 +02:00
end ;
2017-03-01 21:40:57 +01:00
end
else
2019-05-16 00:16:55 +02:00
begin
ChildValue : = AValue. AsType< TValue> ;
2022-08-01 19:11:42 +02:00
ChildJsonObject : = AJSONObject. O[ AName] ;
2019-10-24 15:34:40 +02:00
ChildJsonObject. S[ 'type' ] : = TMVCSerializerHelper. GetTypeKindAsString( ChildValue. TypeInfo. Kind) ;
2020-09-11 13:01:56 +02:00
TValueToJSONObjectProperty( ChildJsonObject, 'value' , ChildValue, stDefault, [ ] , [ ] ) ;
2019-05-16 00:16:55 +02:00
end ;
end
else
2022-05-25 15:13:49 +02:00
begin
2022-07-05 13:20:09 +02:00
lJSONValue : = ConvertRecordToJsonValue( AValue. GetReferenceToRawData, AValue. TypeInfo, stFields, AIgnored, nil ,
nil , lJsonDataType) ;
case lJsonDataType of
jdtArray:
begin
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] : = TJsonArray( lJSONValue) ;
2022-07-05 13:20:09 +02:00
end ;
jdtObject:
begin
2022-08-01 19:11:42 +02:00
AJSONObject. O[ AName] : = TJsonObject( lJSONValue) ;
2022-07-05 13:20:09 +02:00
end
else
begin
lJSONValue. Free;
RaiseSerializationError( 'Invalid JSON Data Type' ) ;
end ;
end ;
2022-05-25 15:13:49 +02:00
end ;
2017-03-01 21:40:57 +01:00
end ;
tkSet:
2022-08-01 19:11:42 +02:00
begin
2022-07-15 20:42:29 +02:00
{$IF defined(BERLINORBETTER)}
2022-08-01 19:11:42 +02:00
lBuffer : = AllocMem( AValue. DataSize) ;
try
AValue. ExtractRawDataNoCopy( lBuffer) ;
AJSONObject. S[ AName] : = SetToString( AValue. TypeInfo, lBuffer) ;
finally
FreeMem( lBuffer)
end ;
2022-07-15 20:42:29 +02:00
{$ELSE}
2022-08-01 19:11:42 +02:00
raise EMVCSerializationException. CreateFmt
( 'Cannot serialize property or field "%s" of TypeKind tkSet in this Delphi version.' , [ AName] ) ;
2022-07-15 20:42:29 +02:00
{$ENDIF}
2022-08-01 19:11:42 +02:00
end ;
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
2022-07-22 19:55:27 +02:00
lCurrentArrayItem : = AValue. GetArrayElement( I) ;
case lCurrentArrayItem. Kind of
2019-05-17 16:15:18 +02:00
tkChar, tkString, tkWChar, tkLString, tkWString, tkUString:
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( lCurrentArrayItem. AsString) ;
2019-05-17 16:15:18 +02:00
tkInteger:
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( lCurrentArrayItem. AsInteger) ;
2019-05-17 16:15:18 +02:00
tkInt64:
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( lCurrentArrayItem. AsInt64) ;
2019-11-03 16:16:35 +01:00
tkFloat:
2022-07-22 19:55:27 +02:00
begin
2022-08-01 19:11:42 +02:00
if lCurrentArrayItem. TypeInfo = TypeInfo( TDate) then
begin
AJSONObject. A[ AName] . Add( DateToISODate( lCurrentArrayItem. AsExtended) ) ;
end
else if lCurrentArrayItem. TypeInfo = TypeInfo( TTime) then
begin
AJSONObject. A[ AName] . Add( TimeToISOTime( lCurrentArrayItem. AsExtended) ) ;
end
else if lCurrentArrayItem. TypeInfo = TypeInfo( TDateTime) then
begin
AJSONObject. A[ AName] . Add( DateTimeToISOTimeStamp( lCurrentArrayItem. AsExtended) ) ;
end
else
begin
AJSONObject. A[ AName] . Add( lCurrentArrayItem. AsExtended) ;
end ;
2022-07-22 19:55:27 +02:00
end ;
2020-11-27 15:13:17 +01:00
tkEnumeration:
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( lCurrentArrayItem. AsBoolean) ;
2020-09-10 23:48:34 +02:00
tkClass:
2020-09-11 13:01:56 +02:00
begin
2022-07-22 19:55:27 +02:00
Obj : = lCurrentArrayItem. AsObject;
2021-01-27 20:25:35 +01:00
if Obj = nil then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( TJsonObject( nil ) ) ;
2021-01-27 20:25:35 +01:00
end
else
begin
lJSONValue : = ConvertObjectToJsonValue( Obj, GetSerializationType( Obj) , [ ] , nil , nil , lJsonDataType) ;
case lJsonDataType of
jdtArray:
begin
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( TJsonArray( lJSONValue) ) ;
2021-01-27 20:25:35 +01:00
end ;
jdtObject:
begin
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( TJsonObject( lJSONValue) ) ;
2021-01-27 20:25:35 +01:00
end ;
else
2020-09-11 13:01:56 +02:00
begin
2021-01-27 20:25:35 +01:00
lJSONValue. Free;
RaiseSerializationError( 'Invalid JSON Type for ' + AName) ;
2020-09-11 13:01:56 +02:00
end ;
end ;
end ;
end ;
2022-07-05 14:42:41 +02:00
tkRecord:
begin
2022-07-22 19:55:27 +02:00
if lCurrentArrayItem. IsEmpty then
2022-07-05 14:42:41 +02:00
begin
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( TJsonObject( nil ) ) ;
2022-07-05 14:42:41 +02:00
end
else
begin
2022-08-01 19:11:42 +02:00
lJSONValue : = ConvertRecordToJsonValue( AValue. GetReferenceToRawArrayElement( I) ,
lCurrentArrayItem. TypeInfo, stFields, [ ] , nil , nil , lJsonDataType) ;
2022-07-05 14:42:41 +02:00
case lJsonDataType of
jdtArray:
begin
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( TJsonArray( lJSONValue) ) ;
2022-07-05 14:42:41 +02:00
end ;
jdtObject:
begin
2022-08-01 19:11:42 +02:00
AJSONObject. A[ AName] . Add( TJsonObject( lJSONValue) ) ;
2022-07-05 14:42:41 +02:00
end ;
else
begin
lJSONValue. Free;
RaiseSerializationError( 'Invalid JSON Type for ' + AName) ;
end ;
end ;
end ;
end ;
2019-05-17 16:15:18 +02:00
else
2020-09-10 23:48:34 +02:00
begin
2022-08-01 19:11:42 +02:00
raise EMVCSerializationException. CreateFmt( 'Cannot serialize property or field "%s"' , [ AName] ) ;
2020-09-10 23:48:34 +02:00
end ;
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 ;
2020-09-11 13:01:56 +02:00
function TMVCJsonDataObjectsSerializer. ConvertObjectToJsonValue( const AObject: TObject;
2022-08-28 13:06:16 +02:00
const AType: TMVCSerializationType; const AIgnoredFields: TMVCIgnoredList;
2020-09-23 23:33:30 +02:00
const ADataSetSerializationCallback: TMVCDataSetFieldSerializationAction;
2021-01-27 20:25:35 +01:00
const ASerializationAction: TMVCSerializationAction; out AJsonDataType: TJsonDataType) : TJsonBaseObject;
2020-09-11 13:01:56 +02:00
var
lList: IMVCList;
I: Integer ;
lValue: TValue;
lObj: TObject;
lJSONValue: TJsonBaseObject;
lJsonDataType: TJsonDataType;
2020-11-13 09:31:20 +01:00
lLinks: IMVCLinks;
2020-09-11 13:01:56 +02:00
begin
Result : = nil ;
try
if AObject is TDataSet then
begin
Result : = TJsonArray. Create;
AJsonDataType : = jdtArray;
2024-06-08 23:05:46 +02:00
DataSetToJsonArray( TDataSet( AObject) , TJsonArray( Result ) , TMVCNameCase. ncUseDefault, [ ] ,
2021-01-27 20:25:35 +01:00
ADataSetSerializationCallback) ;
2020-09-11 13:01:56 +02:00
end
else if AObject is TJsonObject then
begin
AJsonDataType : = jdtObject;
2020-09-11 13:37:45 +02:00
Result : = TJsonObject( TJsonObject( AObject) . Clone) ;
end
else if AObject is TJsonArray then
begin
AJsonDataType : = jdtArray;
Result : = TJsonArray( TJsonArray( AObject) . Clone) ;
2020-09-11 13:01:56 +02:00
end
2021-01-27 20:25:35 +01:00
else if AObject = nil then
begin
AJsonDataType : = jdtObject;
Result : = nil ;
end
2020-09-11 13:01:56 +02:00
else
begin
lList : = TDuckTypedList. Wrap( AObject) ;
if Assigned( lList) then
begin
Result : = TJsonArray. Create; // ChildJsonArray := AJsonObject.A[AName];
AJsonDataType : = jdtArray;
for I : = 0 to lList. Count - 1 do
begin
if lList. ItemIsObject( I, lValue) then
begin
lObj : = lValue. AsObject; // ChildList.GetItem(I);
if Assigned( lObj) then
begin
2022-08-28 13:06:16 +02:00
lJSONValue : = ConvertObjectToJsonValue( lObj, GetSerializationType( lObj, AType) , AIgnoredFields, nil ,
2021-01-27 20:25:35 +01:00
ASerializationAction, lJsonDataType) ;
2020-09-11 13:01:56 +02:00
case lJsonDataType of
jdtObject:
begin
TJsonArray( Result ) . Add( TJsonObject( lJSONValue) ) ;
end ;
jdtArray:
begin
TJsonArray( Result ) . Add( TJsonArray( lJSONValue) ) ;
end ;
else
begin
2020-09-11 13:37:45 +02:00
RaiseSerializationError( 'Invalid JSON type' ) ;
2020-09-11 13:01:56 +02:00
end ;
end ;
end
else
begin
TJsonArray( Result ) . Add( TJsonObject( nil ) ) ;
end ;
end
else
begin
AddTValueToJsonArray( lValue, TJsonArray( Result ) ) ;
end ;
end ;
end
else
begin
Result : = TJsonObject. Create;
AJsonDataType : = jdtObject;
2020-11-13 09:31:20 +01:00
lLinks : = TMVCLinks. Create;
2021-01-27 20:25:35 +01:00
InternalObjectToJsonObject( AObject, TJsonObject( Result ) , GetSerializationType( AObject, AType) ,
2022-08-28 13:06:16 +02:00
AIgnoredFields, ASerializationAction, lLinks, nil ) ;
2020-09-11 13:01:56 +02:00
end ;
end ;
except
2020-09-11 13:37:45 +02:00
FreeAndNil( Result ) ;
2020-09-11 13:01:56 +02:00
raise ;
end ;
end ;
2022-07-05 13:20:09 +02:00
function TMVCJsonDataObjectsSerializer. ConvertRecordToJsonValue( const ARecord: Pointer ;
2022-08-01 19:11:42 +02:00
const ARecordTypeInfo: PTypeInfo; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
2022-07-05 13:20:09 +02:00
const ADataSetSerializationCallback: TMVCDataSetFieldSerializationAction;
const ASerializationAction: TMVCSerializationAction; out AJsonDataType: TJsonDataType) : TJsonBaseObject;
var
lLinks: IMVCLinks;
begin
Result : = nil ;
try
if ARecord = nil then
begin
AJsonDataType : = jdtObject;
Result : = nil ;
end
else
begin
2022-07-05 14:42:41 +02:00
Result : = TJsonObject. Create;
AJsonDataType : = jdtObject;
lLinks : = TMVCLinks. Create;
2022-08-01 19:11:42 +02:00
InternalRecordToJsonObject( ARecord, ARecordTypeInfo, TJsonObject( Result ) , stFields, AIgnoredAttributes,
ASerializationAction, lLinks, nil ) ;
2022-07-05 13:20:09 +02:00
end ;
except
FreeAndNil( Result ) ;
raise ;
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
2021-01-27 20:25:35 +01:00
2019-10-24 15:34:40 +02:00
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) ) ) ;
2024-10-03 23:38:50 +02:00
ftTimeStampOffset:
AJsonArray. Add( DateTimeToISOTimeStamp( SQLTimeStampOffsetToDateTime( ADataSet. Fields[ lField. I] . AsSQLTimeStampOffset) ) ) ;
2019-10-24 15:34:40 +02:00
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
2024-04-29 12:50:25 +02:00
ADataSet. First;
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
2024-04-29 12:50:25 +02:00
ADataSet. First;
2019-10-24 15:34:40 +02:00
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 ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. 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) ;
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 ;
2020-04-20 17:56:17 +02:00
lFName: string ;
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
2021-01-27 20:25:35 +01:00
2017-03-29 14:49:35 +02:00
begin
2019-09-25 09:14:09 +02:00
if Assigned( ASerializationCallback) then
begin
lHandled : = False ;
2022-08-01 19:11:42 +02:00
ASerializationCallback( ADataSet. Fields[ lField. I] , AJSONObject, lHandled) ;
2019-09-25 09:14:09 +02:00
if lHandled then
begin
continue;
end ;
end ;
2020-04-20 17:56:17 +02:00
lFName : = TMVCSerializerHelper. ApplyNameCase( ANameCase, lField. FieldName) ;
2019-04-17 16:47:07 +02:00
if ADataSet. Fields[ lField. I] . IsNull then
2022-08-01 19:11:42 +02:00
AJSONObject[ lFName] : = 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:
2022-08-01 19:11:42 +02:00
AJSONObject. B[ lFName] : = 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:
2022-08-01 19:11:42 +02:00
AJSONObject. I[ lFName] : = ADataSet. Fields[ lField. I] . AsInteger;
2017-03-29 14:49:35 +02:00
2019-09-01 12:15:30 +02:00
ftLargeint, ftAutoInc, ftLongword:
2022-08-01 19:11:42 +02:00
AJSONObject. L[ lFName] : = ADataSet. Fields[ lField. I] . AsLargeInt;
2018-01-29 17:30:53 +01:00
{$IFDEF TOKYOORBETTER}
2017-12-12 20:04:01 +01:00
ftGuid:
2022-08-01 19:11:42 +02:00
AJSONObject. S[ lFName] : = 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:
2022-08-01 19:11:42 +02:00
AJSONObject. F[ lFName] : = ADataSet. Fields[ lField. I] . AsFloat;
2017-03-29 14:49:35 +02:00
2017-09-28 00:14:34 +02:00
ftString, ftMemo:
2022-08-01 19:11:42 +02:00
AJSONObject. S[ lFName] : = ADataSet. Fields[ lField. I] . AsString;
2017-09-28 00:14:34 +02:00
ftWideString, ftWideMemo:
2022-08-01 19:11:42 +02:00
AJSONObject. S[ lFName] : = ADataSet. Fields[ lField. I] . AsWideString;
2017-03-29 14:49:35 +02:00
ftDate:
2022-08-01 19:11:42 +02:00
AJSONObject. S[ lFName] : = DateToISODate( ADataSet. Fields[ lField. I] . AsDateTime) ;
2017-03-29 14:49:35 +02:00
ftDateTime:
2022-08-01 19:11:42 +02:00
AJSONObject. S[ lFName] : = DateTimeToISOTimeStamp( ADataSet. Fields[ lField. I] . AsDateTime) ;
2017-03-29 14:49:35 +02:00
2017-09-07 00:10:21 +02:00
ftTime:
2022-08-01 19:11:42 +02:00
AJSONObject. S[ lFName] : = 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:
2022-08-01 19:11:42 +02:00
AJSONObject. S[ lFName] : = DateTimeToISOTimeStamp
2021-01-27 20:25:35 +01:00
( SQLTimeStampToDateTime( ADataSet. Fields[ lField. I] . AsSQLTimeStamp) ) ;
2017-09-07 00:10:21 +02:00
2024-03-19 16:05:17 +01:00
ftTimeStampOffset:
AJSONObject. S[ lFName] : = DateTimeToISOTimeStamp
( SQLTimeStampOffsetToDateTime( ADataSet. Fields[ lField. I] . AsSQLTimeStampOffset) ) ;
2017-03-29 14:49:35 +02:00
ftCurrency:
2022-08-01 19:11:42 +02:00
AJSONObject. F[ lFName] : = ADataSet. Fields[ lField. I] . AsCurrency;
2017-03-29 14:49:35 +02:00
ftFMTBcd, ftBCD:
2022-08-01 19:11:42 +02:00
AJSONObject. F[ lFName] : = 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) ;
2022-08-01 19:11:42 +02:00
AJSONObject. S[ lFName] : = 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
2022-08-01 19:11:42 +02:00
lChildJsonArray : = AJSONObject. A[ lField. FieldName] ;
2019-04-16 23:12:19 +02:00
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
2022-08-01 19:11:42 +02:00
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
2024-03-19 16:05:17 +01:00
raise EMVCSerializationException. CreateFmt( 'Cannot find type for field "%s" - TFieldType = %s' , [ lField. FieldName, GetEnumName( TypeInfo( TFieldType) , Ord( lField. DataType) ) ] ) ;
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;
2020-09-07 11:28:53 +02:00
const AClazz: TClass; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
const ARootNode: string ) ;
2017-03-01 21:40:57 +01:00
var
2022-08-01 19:11:42 +02:00
JSONArray: TJDOJsonArray;
2020-09-07 11:28:53 +02:00
JsonBase: TJDOJsonBaseObject;
2020-09-11 13:01:56 +02:00
JSONObject: TJDOJsonObject;
2017-03-01 21:40:57 +01:00
ObjList: IMVCList;
begin
if ( ASerializedList = EmptyStr) then
2020-04-09 17:01:33 +02:00
raise EMVCException. Create( HTTP_STATUS. BadRequest, 'Invalid body' ) ;
2017-03-01 21:40:57 +01:00
if not Assigned( AList) then
Exit;
2021-06-01 15:10:45 +02:00
if GetTypeSerializers. ContainsKey( AList. ClassInfo) then
begin
if ARootNode. IsEmpty then
begin
2022-08-01 19:11:42 +02:00
JSONArray : = TJDOJsonArray. Parse( ASerializedList) as TJDOJsonArray;
2021-06-01 15:10:45 +02:00
end
else
begin
try
JsonBase : = TJDOJsonObject. Parse( ASerializedList) ;
if not( JsonBase is TJDOJsonObject) then
begin
2024-06-10 00:18:02 +02:00
JsonBase. Free;
2021-06-01 15:10:45 +02:00
raise EMVCSerializationException. CreateFmt( 'Invalid JSON. Expected %s got %s' ,
[ TJDOJsonObject. ClassName, JsonBase. ClassName] ) ;
end ;
JSONObject : = TJDOJsonObject( JsonBase) ;
except
on E: EJsonParserException do
begin
raise EMVCException. Create( HTTP_STATUS. BadRequest, E. Message ) ;
end ;
end ;
2022-08-01 19:11:42 +02:00
JSONArray : = JSONObject. A[ ARootNode] as TJDOJsonArray;
2021-06-01 15:10:45 +02:00
end ;
try
2022-08-01 19:11:42 +02:00
GetTypeSerializers. Items[ AList. ClassInfo] . DeserializeRoot( JSONArray, AList, [ ] ) ;
2021-06-01 15:10:45 +02:00
Exit;
finally
2022-08-01 19:11:42 +02:00
JSONArray. Free;
2021-06-01 15:10:45 +02:00
end ;
end ;
2017-03-01 21:40:57 +01:00
ObjList : = TDuckTypedList. Wrap( AList) ;
if Assigned( ObjList) then
begin
2021-08-31 17:05:11 +02:00
JsonBase : = TJDOJsonObject. Parse( ASerializedList) ;
try
2020-09-07 11:28:53 +02:00
try
2021-08-31 17:05:11 +02:00
if ARootNode. IsEmpty then
2020-09-07 11:28:53 +02:00
begin
2021-08-31 17:05:11 +02:00
if not( JsonBase is TJDOJsonArray) then
begin
raise EMVCSerializationException. CreateFmt( 'Invalid JSON. Expected %s got %s' ,
[ TJDOJsonArray. ClassName, JsonBase. ClassName] ) ;
end ;
2022-08-01 19:11:42 +02:00
JSONArray : = TJDOJsonArray( JsonBase) ;
2021-08-31 17:05:11 +02:00
end
else
begin
if not( JsonBase is TJDOJsonObject) then
begin
raise EMVCSerializationException. CreateFmt( 'Invalid JSON. Expected %s got %s' ,
[ TJDOJsonObject. ClassName, JsonBase. ClassName] ) ;
end ;
JSONObject : = TJDOJsonObject( JsonBase) ;
2022-08-01 19:11:42 +02:00
JSONArray : = JSONObject. A[ ARootNode] as TJDOJsonArray;
2020-09-07 11:28:53 +02:00
end ;
except
on E: EJsonParserException do
begin
raise EMVCException. Create( HTTP_STATUS. BadRequest, E. Message ) ;
end ;
end ;
2022-08-01 19:11:42 +02:00
JsonArrayToList( JSONArray, ObjList, AClazz, AType, AIgnoredAttributes) ;
2017-03-01 21:40:57 +01:00
finally
2021-08-31 17:05:11 +02:00
JsonBase. Free;
2017-03-01 21:40:57 +01:00
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
2020-04-09 17:01:33 +02:00
raise EMVCException. Create( HTTP_STATUS. BadRequest, 'Invalid body' ) ;
2018-10-31 01:07:23 +01:00
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
2020-04-09 17:01:33 +02:00
raise EMVCException. Create( HTTP_STATUS. BadRequest, 'Invalid body' ) ;
2018-10-31 01:07:23 +01:00
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
2020-04-09 17:01:33 +02:00
if not( ADataSet. State in [ dsInsert, dsEdit] ) then
2020-03-20 23:08:45 +01:00
begin
ADataSet. Edit;
end ;
2019-01-18 19:04:01 +01:00
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 ;
2024-04-29 12:50:25 +02:00
function TMVCJsonDataObjectsSerializer. JsonArrayToArray(
const AJsonArray: TJDOJsonArray;
const ATypeInfo: PTypeInfo) : TValue;
2022-07-10 23:30:00 +02:00
type
2024-04-29 12:50:25 +02:00
TSetOfTypeElement = ( xString, xByte, xInt, xLong, xFloat, xBool) ;
2022-07-10 23:30:00 +02:00
TSetOfType = set of TSetOfTypeElement;
2019-10-24 15:34:40 +02:00
var
I: Integer ;
2020-04-09 17:01:33 +02:00
lStrArr: TArray< string > ;
2024-04-29 12:50:25 +02:00
lByteArr: TArray< Byte > ;
2019-10-24 15:34:40 +02:00
lIntArr: TArray< Integer > ;
2020-05-06 10:49:08 +02:00
lLongArr: TArray< Int64 > ;
lDoubleArr: TArray< Double > ;
2020-11-27 15:13:17 +01:00
lBoolArr: TArray< Boolean > ;
2022-07-10 23:30:00 +02:00
lSetOfType: TSetOfType;
lEl: TSetOfTypeElement;
2019-05-17 16:15:18 +02:00
begin
2022-07-10 23:30:00 +02:00
lSetOfType : = [ ] ;
2022-08-01 19:11:42 +02:00
{ TODO -oDanieleT -cGeneral : I dont like this... }
2019-05-17 16:15:18 +02:00
for I : = 0 to Pred( AJsonArray. Count) do
2020-05-06 10:49:08 +02:00
begin
2019-05-17 16:15:18 +02:00
case AJsonArray. types[ 0 ] of
2019-10-24 15:34:40 +02:00
jdtString:
2022-08-01 19:11:42 +02:00
begin
Include( lSetOfType, xString) ;
lStrArr : = lStrArr + [ AJsonArray. Items[ I] . Value] ;
end ;
2024-04-29 12:50:25 +02:00
jdtInt, jdtLong:
2022-08-01 19:11:42 +02:00
begin
2024-04-29 12:50:25 +02:00
if ATypeInfo = TypeInfo( TArray< Int64 > ) then
begin
Include( lSetOfType, xLong) ;
lLongArr : = lLongArr + [ AJsonArray. Items[ I] . LongValue] ;
end
else
if ATypeInfo = TypeInfo( TArray< Byte > ) then
begin
Include( lSetOfType, xByte) ;
lByteArr : = lByteArr + [ AJsonArray. Items[ I] . IntValue] ;
end
else
begin
Include( lSetOfType, xInt) ;
lIntArr : = lIntArr + [ AJsonArray. Items[ I] . IntValue] ;
end ;
2022-08-01 19:11:42 +02:00
end ;
2020-05-06 10:49:08 +02:00
jdtFloat:
2022-08-01 19:11:42 +02:00
begin
Include( lSetOfType, xFloat) ;
lDoubleArr : = lDoubleArr + [ AJsonArray. Items[ I] . FloatValue] ;
end ;
2020-11-27 15:13:17 +01:00
jdtBool:
2022-08-01 19:11:42 +02:00
begin
Include( lSetOfType, xBool) ;
lBoolArr : = lBoolArr + [ AJsonArray. Items[ I] . BoolValue] ;
end ;
2022-07-10 23:30:00 +02:00
end ;
end ;
I : = 0 ;
for lEl in lSetOfType do
begin
Inc( I) ;
if I > 1 then
begin
raise EMVCDeserializationException. Create( 'Types in the array must be homogeneous' ) ;
2019-05-17 16:15:18 +02:00
end ;
2020-05-06 10:49:08 +02:00
end ;
2019-05-17 16:15:18 +02:00
2019-10-24 15:34:40 +02:00
if Length( lStrArr) > 0 then
2022-07-10 23:30:00 +02:00
Exit( TValue. From < TArray < string > > ( lStrArr) ) ;
2024-04-29 12:50:25 +02:00
if Length( lByteArr) > 0 then
Exit( TValue. From < TArray < Byte > > ( lByteArr) ) ;
2022-07-10 23:30:00 +02:00
if Length( lIntArr) > 0 then
Exit( TValue. From < TArray < Integer > > ( lIntArr) ) ;
if Length( lLongArr) > 0 then
Exit( TValue. From < TArray < Int64 > > ( lLongArr) ) ;
if Length( lBoolArr) > 0 then
Exit( TValue. From < TArray < Boolean > > ( lBoolArr) ) ;
if Length( lDoubleArr) > 0 then
Exit( TValue. From < TArray < Double > > ( lDoubleArr) ) ;
Result : = TValue. From < TArray < String > > ( [ ] ) ;
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 ;
2022-08-12 10:50:46 +02:00
lSerializationMetaInfo: TSerializationMetaInfo;
2017-03-13 20:52:11 +01:00
begin
2022-08-12 10:50:46 +02:00
if AJsonArray. Count > 0 then
2017-03-30 15:56:24 +02:00
begin
2022-08-12 10:50:46 +02:00
lSerializationMetaInfo : = TSerializationMetaInfo. CreateFieldsMetaInfo(
ADataSet,
ANameCase,
AIgnoredFields) ;
for I : = 0 to Pred( AJsonArray. Count) do
begin
ADataSet. Append;
JsonObjectToDataSet(
AJsonArray. Items[ I] . ObjectValue,
ADataSet,
lSerializationMetaInfo) ;
ADataSet. Post;
end ;
2017-03-30 15:56:24 +02:00
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) ;
2020-09-22 15:18:22 +02:00
Assert( AJsonArray. Items[ I] . Typ = jdtObject, 'Cannot deserialize non object type in ' + AClazz. QualifiedClassName +
'. [HINT] Move data structure to objects or use manual deserialization.' ) ;
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 ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. JsonDataValueToAttribute( const AObject: TObject; const ARttiMember: TRttiMember;
const AJSONObject: TJDOJsonObject; const AName: string ; var AValue: TValue; const AType: TMVCSerializationType;
2021-08-17 15:10:58 +02:00
const AIgnored: TMVCIgnoredList; const ACustomAttributes: TArray< TCustomAttribute> ) ;
2017-03-01 21:40:57 +01:00
var
ChildObject: TObject;
2021-08-17 15:10:58 +02:00
lOwnedAttribute: MVCOwnedAttribute;
2021-06-01 15:10:45 +02:00
lTypeInfo: PTypeInfo;
2021-08-17 15:10:58 +02:00
lJSONExists: Boolean ;
lJSONIsNull: Boolean ;
lChildObjectAssigned: Boolean ;
2017-03-01 21:40:57 +01:00
begin
2021-08-17 15:10:58 +02:00
ChildObject : = nil ;
2021-06-01 15:10:45 +02:00
lTypeInfo : = AValue. TypeInfo;
if AValue. Kind in [ tkClass, tkInterface] then
begin
2021-08-17 15:10:58 +02:00
if not AValue. IsEmpty then
begin
if AValue. Kind = tkInterface then
ChildObject : = TObject( AValue. AsInterface)
else
ChildObject : = AValue. AsObject;
end ;
2021-06-01 15:10:45 +02:00
if Assigned( ChildObject) then
2021-08-17 15:10:58 +02:00
begin
lTypeInfo : = ChildObject. ClassInfo
end ;
if TMVCSerializerHelper. AttributeExists< MVCOwnedAttribute> ( ACustomAttributes, lOwnedAttribute) then
begin
2022-04-05 17:17:35 +02:00
{
2022-08-01 19:11:42 +02:00
Now, can happens the following situations:
2021-08-17 15:10:58 +02:00
2022-08-01 19:11:42 +02:00
ChildObject JSON Outcome
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1 ) Created Exists The JSON is loaded in the object ( default )
2 ) Created NotExists Leave unchanged
3 ) Created is Null If ChildObject is Owned must be destroyed
4 ) nil Exists If ChildObject is Owned, create it and load the json
5 ) nil NotExists Leave unchanged
6 ) nil is Null Leave unchanged
2021-08-17 15:10:58 +02:00
2022-08-01 19:11:42 +02:00
- - > So, we' ll manage only case 3 and 4 < - -
2021-08-17 15:10:58 +02:00
}
2022-08-01 19:11:42 +02:00
lJSONExists : = AJSONObject. Contains( AName) ;
lJSONIsNull : = lJSONExists and AJSONObject. IsNull( AName) ;
2021-08-17 15:10:58 +02:00
lChildObjectAssigned : = ChildObject < > nil ;
2022-08-01 19:11:42 +02:00
// case 3
2021-08-17 15:10:58 +02:00
if lChildObjectAssigned and lJSONIsNull then
begin
ChildObject. Free;
case AType of
stUnknown, stDefault, stProperties:
TRttiProperty( ARttiMember) . SetValue( AObject, nil ) ;
stFields:
TRttiField( ARttiMember) . SetValue( AObject, nil ) ;
end ;
end
2022-08-01 19:11:42 +02:00
// case 4
2021-08-17 15:10:58 +02:00
else if ( not lChildObjectAssigned) and lJSONExists and ( not lJSONIsNull) then
begin
if lOwnedAttribute. ClassRef < > nil then
begin
ChildObject : = TMVCSerializerHelper. CreateObject( lOwnedAttribute. ClassRef. QualifiedClassName) ;
2022-10-09 15:45:59 +02:00
AValue : = ChildObject; //dt20221006
2021-08-17 15:10:58 +02:00
end
else
begin
case AType of
stUnknown, stDefault, stProperties:
2022-10-09 15:45:59 +02:00
begin
2022-08-01 19:11:42 +02:00
ChildObject : = TMVCSerializerHelper. CreateObject( TRttiProperty( ARttiMember) . PropertyType) ;
2022-10-09 15:45:59 +02:00
AValue : = ChildObject; //dt20221006
end ;
2021-08-17 15:10:58 +02:00
stFields:
2022-10-09 15:45:59 +02:00
begin
2022-08-01 19:11:42 +02:00
ChildObject : = TMVCSerializerHelper. CreateObject( TRttiField( ARttiMember) . FieldType) ;
2022-10-09 15:45:59 +02:00
AValue : = ChildObject; //dt20221006
end ;
2021-08-17 15:10:58 +02:00
end ;
end ;
lTypeInfo : = ChildObject. ClassInfo;
case AType of
stUnknown, stDefault, stProperties:
TRttiProperty( ARttiMember) . SetValue( AObject, ChildObject) ;
stFields:
TRttiField( ARttiMember) . SetValue( AObject, ChildObject) ;
end ;
2022-08-01 19:11:42 +02:00
end ; // end cases
2021-08-17 15:10:58 +02:00
end ;
2021-06-01 15:10:45 +02:00
end ;
if GetTypeSerializers. ContainsKey( lTypeInfo) then
2017-03-01 21:40:57 +01:00
begin
2022-08-01 19:11:42 +02:00
case AJSONObject[ AName] . Typ of
2017-03-01 21:40:57 +01:00
jdtNone:
Exit;
jdtObject:
2019-01-10 17:30:40 +01:00
begin
/// <summary>JsonDataObjects assumes values null as jdtObject</summary>
2022-08-01 19:11:42 +02:00
if AJSONObject[ AName] . ObjectValue < > nil then
GetTypeSerializers. Items[ lTypeInfo] . 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:
2022-08-01 19:11:42 +02:00
GetTypeSerializers. Items[ lTypeInfo] . DeserializeAttribute( AValue, AName, AJSONObject[ AName] . ArrayValue,
2018-12-12 11:00:41 +01:00
ACustomAttributes) ;
2017-03-01 21:40:57 +01:00
else
2022-08-01 19:11:42 +02:00
GetTypeSerializers. Items[ lTypeInfo] . DeserializeAttribute( AValue, AName, AJSONObject, ACustomAttributes) ;
2017-03-01 21:40:57 +01:00
end ;
Exit;
end ;
2022-08-01 19:11:42 +02:00
JSONObjectPropertyToTValue( AJSONObject, AName, AType, AIgnored, ChildObject, AValue, ACustomAttributes) ;
2022-04-05 17:17:35 +02:00
end ;
2017-03-01 21:40:57 +01:00
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. JSONObjectPropertyToTValue( AJSONObject: TJsonObject;
const APropertyName: String ; const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList;
var ChildObject: TObject; var AValue: TValue; const ACustomAttributes: TArray< TCustomAttribute> ) ;
2022-04-05 17:17:35 +02:00
var
ChildList: IMVCList;
ChildListOfAtt: MVCListOfAttribute;
LClazz: TClass;
2022-08-01 19:11:42 +02:00
lValueTypeInfo: PTypeInfo;
2022-04-05 17:17:35 +02:00
begin
2022-08-01 19:11:42 +02:00
case AJSONObject[ APropertyName] . Typ of
2017-03-01 21:40:57 +01:00
jdtNone:
Exit;
jdtString:
begin
2022-08-10 17:57:59 +02:00
ParseStringAsTValueUsingMetadata(
AJSONObject[ APropertyName] . Value,
AValue. TypeInfo,
'property ' + APropertyName,
ACustomAttributes,
AValue) ;
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
2022-08-01 19:11:42 +02:00
TValue. Make( GetEnumValue( AValue. TypeInfo, GetEnumName( AValue. TypeInfo, AJSONObject[ APropertyName] . IntValue) ) ,
2019-08-12 21:48:33 +02:00
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
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< Integer > ( AJSONObject[ APropertyName] . IntValue) ;
2020-02-03 10:51:40 +01:00
end
else
begin
2022-08-01 19:11:42 +02:00
lValueTypeInfo : = AValue. TypeInfo;
if lValueTypeInfo = TypeInfo( NullableInt32) then
AValue : = TValue. From< NullableInt32> ( NullableInt32( AJSONObject[ APropertyName] . IntValue) )
else if lValueTypeInfo = TypeInfo( NullableUInt32) then
AValue : = TValue. From< NullableUInt32> ( NullableUInt32( AJSONObject[ APropertyName] . IntValue) )
else if lValueTypeInfo = TypeInfo( NullableInt16) then
AValue : = TValue. From< NullableInt16> ( NullableInt16( AJSONObject[ APropertyName] . IntValue) )
else if lValueTypeInfo = TypeInfo( NullableUInt16) then
AValue : = TValue. From< NullableUInt16> ( NullableUInt16( AJSONObject[ APropertyName] . IntValue) )
else if lValueTypeInfo = TypeInfo( NullableInt64) then
AValue : = TValue. From< NullableInt64> ( NullableInt64( AJSONObject[ APropertyName] . LongValue) )
else if lValueTypeInfo = TypeInfo( NullableUInt64) then
AValue : = TValue. From< NullableUInt64> ( NullableUInt64( AJSONObject[ APropertyName] . LongValue) )
else if not TryMapNullableFloat( AValue, AJSONObject, APropertyName) then
2022-04-05 17:17:35 +02:00
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize integer value for "%s"' , [ APropertyName] ) ;
2019-08-12 21:48:33 +02:00
end ;
2017-03-01 21:40:57 +01:00
end ;
jdtLong, jdtULong:
begin
2022-08-01 19:11:42 +02:00
lValueTypeInfo : = AValue. TypeInfo;
if ( lValueTypeInfo = System. TypeInfo( TTimeStamp) ) then
2020-02-03 10:51:40 +01:00
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< TTimeStamp> ( MSecsToTimeStamp( AJSONObject[ APropertyName] . LongValue) )
2020-02-03 10:51:40 +01:00
end
else if ( AValue. Kind < > tkRecord) then { nullables }
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< Int64 > ( AJSONObject[ APropertyName] . LongValue) ;
2020-02-03 10:51:40 +01:00
end
else
begin
2022-08-01 19:11:42 +02:00
if lValueTypeInfo = TypeInfo( NullableInt64) then
AValue : = TValue. From< NullableInt64> ( NullableInt64( AJSONObject[ APropertyName] . LongValue) )
else if lValueTypeInfo = TypeInfo( NullableUInt64) then
AValue : = TValue. From< NullableUInt64> ( NullableUInt64( AJSONObject[ APropertyName] . LongValue) )
else if not TryMapNullableFloat( AValue, AJSONObject, APropertyName) then
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize long integer value for "%s"' ,
[ APropertyName] ) ;
2020-02-03 10:51:40 +01:00
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
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< Double > ( AJSONObject[ APropertyName] . FloatValue) ;
2020-02-03 10:51:40 +01:00
end
else
begin
2022-08-01 19:11:42 +02:00
if not TryMapNullableFloat( AValue, AJSONObject, APropertyName) then
2024-07-22 14:28:32 +02:00
begin
if AValue. TypeInfo = TypeInfo( TTimeStamp) then
begin
AValue : = TValue. From< TTimeStamp> ( MSecsToTimeStamp( AJSONObject[ APropertyName] . LongValue) )
end
else
begin
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize floating-point value for "%s"' , [ APropertyName] ) ;
end ;
end ;
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
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< TDateTime> ( AJSONObject[ APropertyName] . DateTimeValue) ;
2020-02-03 10:51:40 +01:00
end
else
begin
if AValue. TypeInfo = TypeInfo( NullableTDate) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableTDate> ( NullableTDate( AJSONObject[ APropertyName] . DateTimeValue) )
2020-02-03 10:51:40 +01:00
else if AValue. TypeInfo = TypeInfo( NullableTDateTime) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableTDateTime> ( NullableTDateTime( AJSONObject[ APropertyName] . DateTimeValue) )
2020-02-03 10:51:40 +01:00
else if AValue. TypeInfo = TypeInfo( NullableTTime) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableTTime> ( NullableTTime( AJSONObject[ APropertyName] . DateTimeValue) )
2020-02-03 10:51:40 +01:00
else
2022-08-01 19:11:42 +02:00
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize date or time value for "%s"' ,
[ APropertyName] ) ;
2020-02-03 10:51:40 +01:00
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
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< Boolean > ( AJSONObject[ APropertyName] . BoolValue) ;
2020-02-03 10:51:40 +01:00
end
else
begin
if AValue. TypeInfo = TypeInfo( NullableBoolean) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableBoolean> ( NullableBoolean( AJSONObject[ APropertyName] . BoolValue) )
2020-02-03 10:51:40 +01:00
else
2022-04-05 17:17:35 +02:00
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize boolean value for "%s"' , [ APropertyName] ) ;
2020-02-03 10:51:40 +01:00
end ;
2017-03-01 21:40:57 +01:00
jdtObject:
begin
if ( AValue. TypeInfo = System. TypeInfo( TValue) ) then
2022-08-01 11:18:46 +02:00
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. FromVariant( AJSONObject[ APropertyName] . O[ 'value' ] . VariantValue)
2022-08-01 11:18:46 +02:00
end
2017-03-01 21:40:57 +01:00
else
begin
2017-05-17 22:32:45 +02:00
// dt: if a key is null, jsondataobjects assign it the type jdtObject
2022-08-01 19:11:42 +02:00
if AJSONObject[ APropertyName] . ObjectValue < > nil then
2017-05-17 22:32:45 +02:00
begin
2020-06-22 18:09:12 +02:00
case AValue. Kind of
tkInterface:
begin
2022-08-01 19:11:42 +02:00
JsonObjectToObject( AJSONObject. O[ APropertyName] , ChildObject,
2022-04-05 17:17:35 +02:00
GetSerializationType( ChildObject, AType) , AIgnored) ;
2020-06-22 18:09:12 +02:00
end ;
tkClass:
begin
2022-08-01 19:11:42 +02:00
JsonObjectToObject( AJSONObject. O[ APropertyName] , ChildObject,
GetSerializationType( ChildObject, AType) , AIgnored) ;
2020-06-22 18:09:12 +02:00
end ;
tkString, tkUString:
begin
2022-08-01 19:11:42 +02:00
AValue : = AJSONObject. O[ APropertyName] . ToJSON( ) ;
2020-06-22 18:09:12 +02:00
end ;
tkRecord:
begin
if AValue. TypeInfo = TypeInfo( NullableString) then
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableString> ( NullableString( AJSONObject. O[ APropertyName] . ToJSON( ) ) ) ;
2020-06-22 18:09:12 +02:00
end
else
begin
2022-08-01 19:11:42 +02:00
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize object value for "%s"' ,
[ APropertyName] ) ;
2020-06-22 18:09:12 +02:00
end ;
end
end ;
2022-08-01 11:18:46 +02:00
end
else if AValue. Kind = tkRecord then
begin
if String( AValue. TypeInfo. Name ) . StartsWith( 'Nullable' ) then
begin
2022-08-01 19:11:42 +02:00
case GetNullableType( AValue. TypeInfo) of
ntNullableString: NullableString( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableCurrency: NullableCurrency( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableBoolean: NullableBoolean( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableTDate: NullableTDate( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableTTime: NullableTTime( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableTDateTime: NullableTDateTime( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableSingle: NullableSingle( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableDouble: NullableDouble( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableExtended: NullableExtended( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableInt16: NullableInt16( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableUInt16: NullableUInt16( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableInt32: NullableInt32( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableUInt32: NullableUInt32( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableInt64: NullableInt64( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableUInt64: NullableUInt64( AValue. GetReferenceToRawData^ ) . SetNull;
ntNullableTGUID: NullableTGUID( AValue. GetReferenceToRawData^ ) . SetNull;
else
raise EMVCNullable. Create( 'Invalid Nullable Type: ' + String( AValue. TypeInfo. Name ) ) ;
end ;
2022-08-01 11:18:46 +02:00
end ;
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
2024-06-08 23:05:46 +02:00
JsonArrayToDataSet( AJSONObject. A[ APropertyName] , ChildObject as TDataSet, AIgnored, TMVCNameCase. ncUseDefault)
2021-06-01 15:10:45 +02:00
else if GetTypeSerializers. ContainsKey( ChildObject. ClassInfo) then
2020-09-21 12:42:38 +02:00
begin
2022-08-01 19:11:42 +02:00
GetTypeSerializers. Items[ ChildObject. ClassInfo] . DeserializeAttribute( AValue, APropertyName, AJSONObject,
2020-09-21 12:42:38 +02:00
ACustomAttributes) ;
end
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
2022-08-01 19:11:42 +02:00
JsonArrayToList( AJSONObject. A[ APropertyName] , ChildList, LClazz, AType, AIgnored)
2019-02-22 18:19:07 +01:00
else
raise EMVCDeserializationException. CreateFmt
2022-04-05 17:17:35 +02:00
( 'You can not deserialize a list "%s" without the MVCListOf attribute.' , [ APropertyName] ) ;
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
2024-04-29 12:50:25 +02:00
AValue : = JsonArrayToArray( AJSONObject. A[ APropertyName] , AValue. TypeInfo) ;
2019-09-18 13:30:50 +02:00
end ;
2017-03-01 21:40:57 +01:00
end ;
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. JSONObjectPropertyToTValueForRecord( AJSONObject: TJsonObject;
const APropertyName: String ; const AType: TMVCSerializationType; const AIgnored: TMVCIgnoredList; var AValue: TValue;
const ACustomAttributes: TArray< TCustomAttribute> ; const ARTTIField: TRttiField) ;
2017-03-30 15:56:24 +02:00
var
2022-05-25 15:13:49 +02:00
LEnumAsAttr: MVCEnumSerializationAttribute;
LEnumMappedValues: TList< string > ;
LEnumSerType: TMVCEnumSerializationType;
LMappedValueIndex: Integer ;
lOutInteger: Integer ;
lInt: Integer ;
lOutInteger64: Int64 ;
2022-07-11 00:09:59 +02:00
lChildObject: TObject;
2022-07-07 15:09:31 +02:00
lRef: PByte ;
2022-07-10 23:30:00 +02:00
lInnerType: TRttiType;
lCtx: TRttiContext;
lArr: TArray< TValue> ;
lBuff: PByte ;
lInnerTypeAsRecord: TRttiRecordType;
lJItem: TJsonObject;
procedure BuildATValueArrayFromJSONArrayOfJSONObject;
var
I: Integer ;
2017-03-30 15:56:24 +02:00
begin
2022-07-10 23:30:00 +02:00
lInnerTypeAsRecord : = lInnerType. AsRecord;
for I : = 0 to Length( lArr) - 1 do
begin
lBuff : = AValue. GetReferenceToRawArrayElement( I) ;
lJItem : = AJSONObject. A[ APropertyName] . Items[ I] . ObjectValue;
2022-08-01 19:11:42 +02:00
JSONObjectToRecord( lJItem, lInnerTypeAsRecord, lBuff) ;
2022-07-10 23:30:00 +02:00
TValue. MakeWithoutCopy( lBuff, lInnerType. Handle, lArr[ I] ) ;
FreeMem( lBuff, lInnerType. TypeSize) ;
end ;
end ;
2017-03-30 15:56:24 +02:00
2022-07-22 19:55:27 +02:00
procedure BuildATValueArrayFromJSONArrayOfSimpleType;
type
TSetOfTypeElement = ( xString, xInt, xLong, xFloat, xBool) ;
TSetOfType = set of TSetOfTypeElement;
var
I: Integer ;
2022-08-01 19:11:42 +02:00
LJArr: TJsonArray;
2022-07-22 19:55:27 +02:00
lArrayItemType: TJsonDataType;
begin
2022-08-01 19:11:42 +02:00
LJArr : = AJSONObject. A[ APropertyName] ;
if LJArr. Count = 0 then
2022-07-22 19:55:27 +02:00
begin
SetLength( lArr, 0 ) ;
Exit;
end ;
2022-08-01 19:11:42 +02:00
lArrayItemType : = LJArr. types[ 0 ] ;
2017-03-30 15:56:24 +02:00
2022-08-01 19:11:42 +02:00
for I : = 0 to Pred( LJArr. Count) do
2022-07-22 19:55:27 +02:00
begin
case lArrayItemType of
jdtString:
begin
2022-08-01 19:11:42 +02:00
if lInnerType. Handle = TypeInfo( TDate) then
begin
lArr[ I] : = ISODateToDate( LJArr. Items[ I] . Value) ;
end
else if lInnerType. Handle = TypeInfo( TTime) then
begin
lArr[ I] : = ISOTimeToTime( LJArr. Items[ I] . Value) ;
end
else if lInnerType. Handle = TypeInfo( TDateTime) then
begin
lArr[ I] : = ISOTimeStampToDateTime( LJArr. Items[ I] . Value) ;
end
else
begin
lArr[ I] : = LJArr. Items[ I] . Value;
end ;
2017-03-30 15:56:24 +02:00
end ;
2022-07-22 19:55:27 +02:00
jdtInt:
2022-08-01 19:11:42 +02:00
begin
lArr[ I] : = LJArr. Items[ I] . IntValue;
end ;
2022-07-22 19:55:27 +02:00
jdtLong:
2022-08-01 19:11:42 +02:00
begin
lArr[ I] : = LJArr. Items[ I] . LongValue;
end ;
2022-07-22 19:55:27 +02:00
jdtFloat:
2022-08-01 19:11:42 +02:00
begin
lArr[ I] : = LJArr. Items[ I] . FloatValue;
end ;
2022-07-22 19:55:27 +02:00
jdtBool:
2022-08-01 19:11:42 +02:00
begin
lArr[ I] : = LJArr. Items[ I] . BoolValue;
end ;
else
raise EMVCDeserializationException. Create( 'Invalid element in array at property ' + APropertyName) ;
2017-03-30 15:56:24 +02:00
end ;
end ;
end ;
2022-05-25 15:13:49 +02:00
begin
2022-07-11 00:09:59 +02:00
lChildObject : = nil ;
2024-05-01 11:03:49 +02:00
if AJSONObject = nil then
Exit;
2022-08-01 19:11:42 +02:00
case AJSONObject[ APropertyName] . Typ of
2022-05-25 15:13:49 +02:00
jdtNone:
Exit;
jdtString:
begin
if ( AValue. TypeInfo = System. TypeInfo( TDate) ) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< TDate> ( ISODateToDate( AJSONObject[ APropertyName] . Value) )
2022-05-25 15:13:49 +02:00
else if ( AValue. TypeInfo = System. TypeInfo( TDateTime) ) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< TDateTime> ( ISOTimeStampToDateTime( AJSONObject[ APropertyName] . Value) )
2022-05-25 15:13:49 +02:00
else if ( AValue. TypeInfo = System. TypeInfo( TTime) ) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< TTime> ( ISOTimeToTime( AJSONObject[ APropertyName] . Value) )
2022-05-25 15:13:49 +02:00
else if ( AValue. Kind = tkRecord) and ( AValue. TypeInfo < > TypeInfo( TValue) ) then { nullables }
begin
if AValue. TypeInfo = TypeInfo( NullableString) then
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableString> ( NullableString( AJSONObject[ APropertyName] . Value) )
2022-05-25 15:13:49 +02:00
end
else if AValue. TypeInfo = TypeInfo( NullableTDate) then
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableTDate> ( NullableTDate( ISODateToDate( AJSONObject[ APropertyName] . Value) ) )
2022-05-25 15:13:49 +02:00
end
else if AValue. TypeInfo = TypeInfo( NullableTDateTime) then
begin
AValue : = TValue. From< NullableTDateTime>
2022-08-01 19:11:42 +02:00
( NullableTDateTime( ISOTimeStampToDateTime( AJSONObject[ APropertyName] . Value) ) )
2022-05-25 15:13:49 +02:00
end
else if AValue. TypeInfo = TypeInfo( NullableTTime) then
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableTTime> ( NullableTTime( ISOTimeToTime( AJSONObject[ APropertyName] . Value) ) )
2022-05-25 15:13:49 +02:00
end
else
raise EMVCSerializationException. CreateFmt( 'Cannot deserialize property "%s" from string' , [ APropertyName] ) ;
end
else if ( AValue. Kind = tkEnumeration) then
begin
LEnumSerType : = estEnumName;
LEnumMappedValues : = nil ;
if TMVCSerializerHelper. AttributeExists< MVCEnumSerializationAttribute> ( ACustomAttributes, LEnumAsAttr) then
begin
LEnumSerType : = LEnumAsAttr. SerializationType;
LEnumMappedValues : = LEnumAsAttr. MappedValues;
end ;
if LEnumSerType = estEnumName then
begin
2022-08-01 19:11:42 +02:00
TValue. Make( GetEnumValue( AValue. TypeInfo, AJSONObject[ APropertyName] . Value) , AValue. TypeInfo, AValue)
2022-05-25 15:13:49 +02:00
end
else
begin
2022-08-01 19:11:42 +02:00
LMappedValueIndex : = LEnumMappedValues. IndexOf( AJSONObject[ APropertyName] . Value) ;
2022-05-25 15:13:49 +02:00
if LMappedValueIndex < 0 then
raise EMVCSerializationException. CreateFmt( 'Cannot deserialize property "%s" from mapped values' ,
[ APropertyName] ) ;
TValue. Make( GetEnumValue( AValue. TypeInfo, GetEnumName( AValue. TypeInfo, LMappedValueIndex) ) ,
AValue. TypeInfo, AValue)
end ;
end
2022-08-01 19:11:42 +02:00
else if ( AValue. Kind = tkInteger) and ( TryStrToInt( AJSONObject[ APropertyName] . Value, lOutInteger) ) then
2022-05-25 15:13:49 +02:00
begin
AValue : = lOutInteger;
end
2022-08-01 19:11:42 +02:00
else if ( AValue. Kind = tkInt64) and ( TryStrToInt64( AJSONObject[ APropertyName] . Value, lOutInteger64) ) then
2022-05-25 15:13:49 +02:00
begin
AValue : = lOutInteger64;
end
else if AValue. TypeInfo. Kind = tkSet then
begin
2022-08-01 19:11:42 +02:00
lInt : = StringToSet( AValue. TypeInfo, StringReplace( AJSONObject[ APropertyName] . Value, ' ' , '' ,
[ rfReplaceAll] ) ) ;
2022-05-25 15:13:49 +02:00
TValue. Make( lInt, AValue. TypeInfo, AValue) ;
end
else
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< string > ( AJSONObject[ APropertyName] . Value) ;
2022-05-25 15:13:49 +02:00
end ;
end ;
jdtInt:
begin
if ( AValue. Kind = tkEnumeration) then
begin
2022-08-01 19:11:42 +02:00
TValue. Make( GetEnumValue( AValue. TypeInfo, GetEnumName( AValue. TypeInfo, AJSONObject[ APropertyName] . IntValue) ) ,
2022-05-25 15:13:49 +02:00
AValue. TypeInfo, AValue)
end
else if ( AValue. Kind < > tkRecord) then { nullables }
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< Integer > ( AJSONObject[ APropertyName] . IntValue) ;
2022-05-25 15:13:49 +02:00
end
else
begin
if AValue. TypeInfo = TypeInfo( NullableInt32) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableInt32> ( NullableInt32( AJSONObject[ APropertyName] . IntValue) )
2022-05-25 15:13:49 +02:00
else if AValue. TypeInfo = TypeInfo( NullableUInt32) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableUInt32> ( NullableUInt32( AJSONObject[ APropertyName] . IntValue) )
2022-05-25 15:13:49 +02:00
else if AValue. TypeInfo = TypeInfo( NullableInt16) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableInt16> ( NullableInt16( AJSONObject[ APropertyName] . IntValue) )
2022-05-25 15:13:49 +02:00
else if AValue. TypeInfo = TypeInfo( NullableUInt16) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableUInt16> ( NullableUInt16( AJSONObject[ APropertyName] . IntValue) )
2022-05-25 15:13:49 +02:00
else if AValue. TypeInfo = TypeInfo( NullableInt64) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableInt64> ( NullableInt64( AJSONObject[ APropertyName] . LongValue) )
2022-05-25 15:13:49 +02:00
else if AValue. TypeInfo = TypeInfo( NullableUInt64) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableUInt64> ( NullableUInt64( AJSONObject[ APropertyName] . LongValue) )
else if not TryMapNullableFloat( AValue, AJSONObject, APropertyName) then
2022-05-25 15:13:49 +02:00
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize integer value for "%s"' , [ APropertyName] ) ;
end ;
end ;
jdtLong, jdtULong:
begin
if ( AValue. TypeInfo = System. TypeInfo( TTimeStamp) ) then
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< TTimeStamp> ( MSecsToTimeStamp( AJSONObject[ APropertyName] . LongValue) )
2022-05-25 15:13:49 +02:00
end
else if ( AValue. Kind < > tkRecord) then { nullables }
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< Int64 > ( AJSONObject[ APropertyName] . LongValue) ;
2022-05-25 15:13:49 +02:00
end
else
begin
if AValue. TypeInfo = TypeInfo( NullableInt64) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableInt64> ( NullableInt64( AJSONObject[ APropertyName] . LongValue) )
2022-05-25 15:13:49 +02:00
else if AValue. TypeInfo = TypeInfo( NullableUInt64) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableUInt64> ( NullableUInt64( AJSONObject[ APropertyName] . LongValue) )
else if not TryMapNullableFloat( AValue, AJSONObject, APropertyName) then
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize long integer value for "%s"' ,
[ APropertyName] ) ;
2022-05-25 15:13:49 +02:00
end ;
end ;
jdtFloat:
if ( AValue. Kind < > tkRecord) then { nullables }
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< Double > ( AJSONObject[ APropertyName] . FloatValue) ;
2022-05-25 15:13:49 +02:00
end
else
begin
2022-08-01 19:11:42 +02:00
if not TryMapNullableFloat( AValue, AJSONObject, APropertyName) then
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize floating-point value for "%s"' ,
[ APropertyName] ) ;
2022-05-25 15:13:49 +02:00
end ;
jdtDateTime:
if ( AValue. Kind < > tkRecord) then { nullables }
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< TDateTime> ( AJSONObject[ APropertyName] . DateTimeValue) ;
2022-05-25 15:13:49 +02:00
end
else
begin
if AValue. TypeInfo = TypeInfo( NullableTDate) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableTDate> ( NullableTDate( AJSONObject[ APropertyName] . DateTimeValue) )
2022-05-25 15:13:49 +02:00
else if AValue. TypeInfo = TypeInfo( NullableTDateTime) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableTDateTime> ( NullableTDateTime( AJSONObject[ APropertyName] . DateTimeValue) )
2022-05-25 15:13:49 +02:00
else if AValue. TypeInfo = TypeInfo( NullableTTime) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableTTime> ( NullableTTime( AJSONObject[ APropertyName] . DateTimeValue) )
2022-05-25 15:13:49 +02:00
else
2022-08-01 19:11:42 +02:00
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize date or time value for "%s"' ,
[ APropertyName] ) ;
2022-05-25 15:13:49 +02:00
end ;
jdtBool:
if ( AValue. Kind < > tkRecord) then { nullables }
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< Boolean > ( AJSONObject[ APropertyName] . BoolValue) ;
2022-05-25 15:13:49 +02:00
end
else
begin
if AValue. TypeInfo = TypeInfo( NullableBoolean) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableBoolean> ( NullableBoolean( AJSONObject[ APropertyName] . BoolValue) )
2022-05-25 15:13:49 +02:00
else
raise EMVCDeserializationException. CreateFmt( 'Cannot deserialize boolean value for "%s"' , [ APropertyName] ) ;
end ;
jdtObject:
begin
if ( AValue. TypeInfo = System. TypeInfo( TValue) ) then
2022-08-01 19:11:42 +02:00
AValue : = TValue. FromVariant( AJSONObject[ APropertyName] . O[ 'value' ] . VariantValue)
2022-05-25 15:13:49 +02:00
else
begin
// dt: if a key is null, jsondataobjects assign it the type jdtObject
2022-08-01 19:11:42 +02:00
if AJSONObject[ APropertyName] . ObjectValue < > nil then
2022-05-25 15:13:49 +02:00
begin
case AValue. Kind of
tkInterface:
begin
2022-08-01 19:11:42 +02:00
JsonObjectToObject( AJSONObject. O[ APropertyName] , lChildObject,
2022-07-11 00:09:59 +02:00
GetSerializationType( lChildObject, AType) , AIgnored) ;
2022-05-25 15:13:49 +02:00
end ;
tkClass:
begin
2022-08-01 19:11:42 +02:00
JsonObjectToObject( AJSONObject. O[ APropertyName] , lChildObject,
2022-07-11 00:09:59 +02:00
GetSerializationType( lChildObject, AType) , AIgnored) ;
2022-05-25 15:13:49 +02:00
end ;
tkString, tkUString:
begin
2022-08-01 19:11:42 +02:00
AValue : = AJSONObject. O[ APropertyName] . ToJSON( ) ;
2022-05-25 15:13:49 +02:00
end ;
tkRecord:
begin
if AValue. TypeInfo = TypeInfo( NullableString) then
begin
2022-08-01 19:11:42 +02:00
AValue : = TValue. From< NullableString> ( NullableString( AJSONObject. O[ APropertyName] . ToJSON( ) ) ) ;
2022-05-25 15:13:49 +02:00
end
else
begin
2022-07-07 15:09:31 +02:00
lRef : = PByte( AValue. GetReferenceToRawData) ;
2022-08-01 19:11:42 +02:00
JSONObjectToNestedRecordFieldStatic( AJSONObject, ARTTIField, 0 , lRef) ;
2022-05-25 15:13:49 +02:00
end ;
2022-07-07 15:09:31 +02:00
end ;
2022-08-01 19:11:42 +02:00
else
2022-07-10 23:30:00 +02:00
begin
2022-08-01 19:11:42 +02:00
raise Exception. Create( 'Type not suppported: ' + GetEnumName( TypeInfo( TJsonDataType) ,
Ord( AJSONObject[ APropertyName] . Typ) ) ) ;
2022-07-10 23:30:00 +02:00
end ;
2022-05-25 15:13:49 +02:00
end ;
end ;
end ;
end ;
jdtArray:
begin
2022-07-10 23:30:00 +02:00
lCtx : = TRttiContext. Create;
try
if AValue. Kind = tkArray then
2022-05-25 15:13:49 +02:00
begin
2022-07-10 23:30:00 +02:00
if AValue. GetArrayLength < > AJSONObject. A[ APropertyName] . Count then
begin
2022-08-01 19:11:42 +02:00
raise EMVCDeserializationException. Create( Format( 'Wrong array size, expected %d, got %d' ,
[ AValue. GetArrayLength, AJSONObject. A[ APropertyName] . Count] ) ) ;
2022-07-10 23:30:00 +02:00
end ;
SetLength( lArr, AJSONObject. A[ APropertyName] . Count) ;
2022-07-23 01:21:52 +02:00
lInnerType : = lCtx. GetType( AValue. GetArrayElement( 0 ) . TypeInfo) ;
2022-07-10 23:30:00 +02:00
BuildATValueArrayFromJSONArrayOfJSONObject;
AValue : = TValue. FromArray( ARTTIField. FieldType. Handle, lArr) ;
end
else if AValue. Kind = tkDynArray then
begin
SetLength( lArr, AJSONObject. A[ APropertyName] . Count) ;
if Length( lArr) > 0 then
begin
2022-08-01 19:11:42 +02:00
// DT: This line is required to know the typeinfo of an element of the dynamic array
// still not created (see BuildATValueArrayFromJSONArrayOfJSONObject).
// This is required because the dynamic array is still
// not dimensioned here, for a static array this is not necessary.
2022-07-10 23:30:00 +02:00
AValue : = TValue. FromArray( ARTTIField. FieldType. Handle, [ TValue. Empty] ) ;
2022-07-22 19:55:27 +02:00
lInnerType : = lCtx. GetType( AValue. GetArrayElement( 0 ) . TypeInfo) ;
if lInnerType. IsRecord then
begin
BuildATValueArrayFromJSONArrayOfJSONObject;
end
else
begin
BuildATValueArrayFromJSONArrayOfSimpleType;
2022-08-01 19:11:42 +02:00
// raise Exception.Create('Unsupported type: ' + ARTTIField.FieldType.Name);
2022-07-22 19:55:27 +02:00
end ;
2022-07-10 23:30:00 +02:00
end ;
AValue : = TValue. FromArray( ARTTIField. FieldType. Handle, lArr) ;
2022-05-25 15:13:49 +02:00
end
else
begin
2022-07-10 23:30:00 +02:00
raise Exception. Create( 'A JSON Array cannot be mapped to ' + ARTTIField. FieldType. Name ) ;
2022-05-25 15:13:49 +02:00
end ;
2022-07-10 23:30:00 +02:00
finally
lCtx. Free;
2022-05-25 15:13:49 +02:00
end ;
end ;
end ;
end ;
2022-08-12 10:50:46 +02:00
procedure TMVCJsonDataObjectsSerializer. JsonObjectToDataSet(
const AJSONObject: TJDOJsonObject; const ADataSet: TDataSet;
const SerializationMetaInfo: TSerializationMetaInfo) ;
var
Field: TField;
lName: string ;
SS: TStringStream;
SM: TMemoryStream;
NestedDataSet: TDataSet;
begin
if ( ADataSet. State in [ dsInsert, dsEdit] ) then
begin
for Field in ADataSet. Fields do
begin
if SerializationMetaInfo. FieldsMetaInfo[ Field. Index ] . Ignored then
begin
Continue;
end ;
// lName := GetNameAs(ADataSet.Owner, Field.Name, Field.FieldName);
// if (IsIgnoredAttribute(AIgnoredFields, lName)) or (IsIgnoredComponent(ADataSet.Owner, Field.Name)) then
// continue;
// lName := TMVCSerializerHelper.ApplyNameCase(GetNameCase(ADataSet, ANameCase), lName);
lName : = SerializationMetaInfo. FieldsMetaInfo[ Field. Index ] . NameAs;
if not AJSONObject. Contains( lName) then
continue;
if ( AJSONObject[ lName] . Typ = jdtObject) and ( AJSONObject. Values[ lName] . ObjectValue = nil ) then
// Nullable Type
begin
Field. Clear;
continue;
end ;
case Field. DataType of
TFieldType. ftBoolean:
Field. AsBoolean : = AJSONObject. B[ lName] ;
TFieldType. ftInteger, TFieldType. ftSmallint, TFieldType. ftShortint, TFieldType. ftByte, TFieldType. ftLongword,
TFieldType. ftWord, TFieldType. ftAutoInc:
Field. AsInteger : = AJSONObject. I[ lName] ;
TFieldType. ftLargeint:
Field. AsLargeInt : = AJSONObject. L[ lName] ;
TFieldType. ftCurrency:
Field. AsCurrency : = AJSONObject. F[ lName] ;
TFieldType. ftSingle:
Field. AsSingle : = AJSONObject. F[ lName] ;
TFieldType. ftFloat, TFieldType. ftFMTBcd, TFieldType. ftBCD:
Field. AsFloat : = AJSONObject. F[ lName] ;
2024-02-12 18:11:48 +01:00
TFieldType. ftExtended:
Field. AsExtended : = AJSONObject. F[ lName] ;
2022-08-12 10:50:46 +02:00
ftString, ftWideString, ftMemo, ftWideMemo:
Field. AsWideString : = AJSONObject. S[ lName] ;
TFieldType. ftDate:
Field. AsDateTime : = ISODateToDate( AJSONObject. S[ lName] ) ;
TFieldType. ftDateTime, TFieldType. ftTimeStamp:
Field. AsDateTime : = ISOTimeStampToDateTime( AJSONObject. S[ lName] ) ;
2024-10-03 23:38:50 +02:00
TFieldType. ftTimeStampOffset:
Field. AsSQLTimeStampOffset : = DateTimeToSQLTimeStampOffset( ISOTimeStampToDateTime( AJSONObject. S[ lName] ) ) ;
2022-08-12 10:50:46 +02:00
TFieldType. ftTime:
Field. AsDateTime : = ISOTimeToTime( AJSONObject. S[ lName] ) ;
{$IFDEF TOKYOORBETTER}
TFieldType. ftGuid:
Field. AsGuid : = StringToGUID( AJSONObject. S[ lName] ) ;
{$ENDIF}
TFieldType. ftGraphic, TFieldType. ftBlob, TFieldType. ftStream:
begin
SS : = TStringStream. Create( AJSONObject. S[ lName] ) ;
try
SS. Position : = 0 ;
SM : = TMemoryStream. Create;
try
TMVCSerializerHelper. DecodeStream( SS, SM) ;
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
JsonArrayToDataSet(
AJSONObject. A[ lName] ,
NestedDataSet,
SerializationMetaInfo. IgnoredFields,
SerializationMetaInfo. NameCase) ;
end ;
dtObject:
begin
NestedDataSet. Edit;
JsonObjectToDataSet(
AJSONObject. O[ lName] ,
NestedDataSet,
SerializationMetaInfo. IgnoredFields,
SerializationMetaInfo. NameCase) ;
NestedDataSet. Post;
end ;
end ;
end ;
else
raise EMVCDeserializationException. CreateFmt( 'Cannot find type for field "%s"' , [ Field. FieldName] ) ;
end ;
end ;
end ;
end ;
2022-08-01 19:11:42 +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;
2020-04-20 17:56:17 +02:00
lName: string ;
2017-03-30 15:56:24 +02:00
SS: TStringStream;
SM: TMemoryStream;
NestedDataSet: TDataSet;
begin
if ( ADataSet. State in [ dsInsert, dsEdit] ) then
begin
for Field in ADataSet. Fields do
begin
2020-04-20 17:56:17 +02:00
lName : = GetNameAs( ADataSet. Owner, Field. Name , Field. FieldName) ;
2017-03-30 15:56:24 +02:00
2020-04-20 17:56:17 +02:00
if ( IsIgnoredAttribute( AIgnoredFields, lName) ) or ( IsIgnoredComponent( ADataSet. Owner, Field. Name ) ) then
2019-10-24 15:34:40 +02:00
continue;
2017-03-30 15:56:24 +02:00
2022-08-12 10:50:46 +02:00
lName : = TMVCSerializerHelper. ApplyNameCase( GetNameCase( ADataSet, ANameCase) , lName) ;
2017-03-30 15:56:24 +02:00
2022-08-01 19:11:42 +02:00
if not AJSONObject. Contains( lName) then
2019-10-24 15:34:40 +02:00
continue;
2017-03-30 15:56:24 +02:00
2022-08-01 19:11:42 +02:00
if ( AJSONObject[ lName] . Typ = jdtObject) and ( AJSONObject. Values[ lName] . ObjectValue = nil ) then
2019-03-10 16:29:18 +01:00
// 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:
2022-08-01 19:11:42 +02:00
Field. AsBoolean : = AJSONObject. B[ lName] ;
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:
2022-08-01 19:11:42 +02:00
Field. AsInteger : = AJSONObject. I[ lName] ;
2017-03-30 15:56:24 +02:00
TFieldType. ftLargeint:
2022-08-01 19:11:42 +02:00
Field. AsLargeInt : = AJSONObject. L[ lName] ;
2017-03-30 15:56:24 +02:00
TFieldType. ftCurrency:
2022-08-01 19:11:42 +02:00
Field. AsCurrency : = AJSONObject. F[ lName] ;
2017-03-30 15:56:24 +02:00
TFieldType. ftSingle:
2022-08-01 19:11:42 +02:00
Field. AsSingle : = AJSONObject. F[ lName] ;
2017-03-30 15:56:24 +02:00
TFieldType. ftFloat, TFieldType. ftFMTBcd, TFieldType. ftBCD:
2022-08-01 19:11:42 +02:00
Field. AsFloat : = AJSONObject. F[ lName] ;
2017-03-30 15:56:24 +02:00
2024-02-12 18:11:48 +01:00
TFieldType. ftExtended:
Field. AsExtended : = AJSONObject. F[ lName] ;
2017-03-30 15:56:24 +02:00
ftString, ftWideString, ftMemo, ftWideMemo:
2022-08-01 19:11:42 +02:00
Field. AsWideString : = AJSONObject. S[ lName] ;
2017-03-30 15:56:24 +02:00
TFieldType. ftDate:
2022-08-01 19:11:42 +02:00
Field. AsDateTime : = ISODateToDate( AJSONObject. S[ lName] ) ;
2017-03-30 15:56:24 +02:00
2020-11-05 15:42:31 +01:00
TFieldType. ftDateTime, TFieldType. ftTimeStamp:
2022-08-01 19:11:42 +02:00
Field. AsDateTime : = ISOTimeStampToDateTime( AJSONObject. S[ lName] ) ;
2017-03-30 15:56:24 +02:00
2024-03-19 16:05:17 +01:00
TFieldType. ftTimeStampOffset:
2024-10-03 23:38:50 +02:00
Field. AsSQLTimeStampOffset : = DateTimeToSQLTimeStampOffset( ISOTimeStampToDateTime( AJSONObject. S[ lName] ) ) ;
2024-03-19 16:05:17 +01:00
2020-11-05 15:42:31 +01:00
TFieldType. ftTime:
2022-08-01 19:11:42 +02:00
Field. AsDateTime : = ISOTimeToTime( AJSONObject. S[ lName] ) ;
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:
2022-08-01 19:11:42 +02:00
Field. AsGuid : = StringToGUID( AJSONObject. S[ lName] ) ;
2018-01-29 17:30:53 +01:00
{$ENDIF}
2017-03-30 15:56:24 +02:00
TFieldType. ftGraphic, TFieldType. ftBlob, TFieldType. ftStream:
begin
2022-08-01 19:11:42 +02:00
SS : = TStringStream. Create( AJSONObject. S[ lName] ) ;
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
2022-08-01 19:11:42 +02:00
JsonArrayToDataSet( AJSONObject. A[ lName] , NestedDataSet, AIgnoredFields, ANameCase) ;
2017-03-30 15:56:24 +02:00
end ;
dtObject:
begin
NestedDataSet. Edit;
2022-08-01 19:11:42 +02:00
JsonObjectToDataSet( AJSONObject. O[ lName] , 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 ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. JsonObjectToObject( const AJSONObject: TJDOJsonObject; const AObject: TObject;
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList) ;
2017-03-01 21:40:57 +01:00
var
2020-05-04 12:39:54 +02:00
lObjType: TRttiType;
lProp: TRttiProperty;
lFld: TRttiField;
lAttributeValue: TValue;
2018-08-05 20:31:33 +02:00
lKeyName: string ;
2020-04-09 17:01:33 +02:00
lErrMsg: string ;
2017-03-01 21:40:57 +01:00
begin
2021-02-12 18:44:43 +01:00
if AObject = nil then
begin
Exit;
end ;
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 ;
2022-08-01 19:11:42 +02:00
TJsonObject( AObject) . Assign( AJSONObject) ;
2019-11-05 14:40:39 +01:00
Exit;
end ;
2020-05-04 12:39:54 +02:00
lProp : = nil ;
lFld : = nil ;
2020-04-09 17:01:33 +02:00
2020-05-04 12:39:54 +02:00
lObjType : = 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
2020-05-04 12:39:54 +02:00
for lProp in lObjType. GetProperties do
2018-10-14 18:23:20 +02:00
begin
2017-05-25 12:30:08 +02:00
2018-07-16 12:34:07 +02:00
{$IFDEF AUTOREFCOUNT}
2020-06-18 14:49:06 +02:00
if TMVCSerializerHelper. IsAPropertyToSkip( lProp. 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}
2020-05-04 12:39:54 +02:00
if ( ( not TMVCSerializerHelper. HasAttribute< MVCDoNotDeserializeAttribute> ( lProp) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, lProp. Name ) ) and
( lProp. IsWritable or lProp. GetValue( AObject) . IsObject) ) then
2018-10-14 18:23:20 +02:00
begin
2020-05-04 12:39:54 +02:00
lAttributeValue : = lProp. GetValue( AObject) ;
lKeyName : = TMVCSerializerHelper. GetKeyName( lProp, lObjType) ;
2022-08-01 19:11:42 +02:00
JsonDataValueToAttribute( AObject, lProp, AJSONObject, lKeyName, lAttributeValue, AType,
AIgnoredAttributes, lProp. GetAttributes) ;
2020-06-18 14:49:06 +02:00
if ( not lAttributeValue. IsEmpty) and ( not lAttributeValue. IsObject) and lProp. IsWritable then
begin
2020-05-04 12:39:54 +02:00
lProp. SetValue( AObject, lAttributeValue) ;
2020-06-18 14:49:06 +02:00
end ;
2018-10-14 18:23:20 +02:00
end ;
end ;
except
on E: EInvalidCast do
2017-03-01 21:40:57 +01:00
begin
2020-05-04 12:39:54 +02:00
if lProp < > nil then
2020-04-09 17:01:33 +02:00
begin
lErrMsg : = Format( 'Invalid class typecast for property "%s" [Expected: %s, Actual: %s]' ,
2022-08-01 19:11:42 +02:00
[ lKeyName, lProp. PropertyType. ToString( ) , JDO_TYPE_DESC[ AJSONObject[ lKeyName] . Typ] ] ) ;
2020-04-09 17:01:33 +02:00
end
else
begin
lErrMsg : = Format( 'Invalid class typecast for property "%s" [Actual: %s]' ,
2022-08-01 19:11:42 +02:00
[ lKeyName, JDO_TYPE_DESC[ AJSONObject[ lKeyName] . Typ] ] ) ;
2020-04-09 17:01:33 +02:00
end ;
raise EMVCException. Create( HTTP_STATUS. BadRequest, lErrMsg) ;
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
2020-05-04 12:39:54 +02:00
for lFld in lObjType. GetFields do
if ( not TMVCSerializerHelper. HasAttribute< MVCDoNotDeserializeAttribute> ( lFld) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, lFld. Name ) ) then
2018-08-05 20:31:33 +02:00
begin
2020-05-04 12:39:54 +02:00
lAttributeValue : = lFld. GetValue( AObject) ;
lKeyName : = TMVCSerializerHelper. GetKeyName( lFld, lObjType) ;
2022-08-01 19:11:42 +02:00
JsonDataValueToAttribute( AObject, lFld, AJSONObject, lKeyName, lAttributeValue, AType, AIgnoredAttributes,
lFld. GetAttributes) ;
2021-08-17 15:10:58 +02:00
if ( not lAttributeValue. IsEmpty) and ( not lAttributeValue. IsObject) then
2020-05-04 12:39:54 +02:00
lFld. SetValue( AObject, lAttributeValue) ;
2018-08-05 20:31:33 +02:00
end ;
except
on E: EInvalidCast do
2017-03-01 21:40:57 +01:00
begin
2020-05-04 12:39:54 +02:00
if lFld < > nil then
2020-04-09 17:01:33 +02:00
begin
lErrMsg : = Format( 'Invalid class typecast for field "%s" [Expected: %s, Actual: %s]' ,
2022-08-01 19:11:42 +02:00
[ lKeyName, lFld. FieldType. ToString( ) , JDO_TYPE_DESC[ AJSONObject[ lKeyName] . Typ] ] ) ;
2020-04-09 17:01:33 +02:00
end
else
begin
lErrMsg : = Format( 'Invalid class typecast for field "%s" [Actual: %s]' ,
2022-08-01 19:11:42 +02:00
[ lKeyName, JDO_TYPE_DESC[ AJSONObject[ lKeyName] . Typ] ] ) ;
2020-04-09 17:01:33 +02:00
end ;
raise EMVCException. Create( HTTP_STATUS. BadRequest, lErrMsg) ;
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 ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. JSONObjectToRecord( const JSONObject: TJsonObject; RTTIType: TRttiRecordType;
out Buffer: PByte ) ;
2022-05-25 15:13:49 +02:00
var
lTypeSize: Integer ;
AIgnoredAttributes: TMVCIgnoredList;
lKeyName: string ;
lAttributeValue: TValue;
lErrMsg: string ;
2022-08-01 19:11:42 +02:00
lField: TRttiField;
2022-05-25 15:13:49 +02:00
begin
2022-07-10 23:30:00 +02:00
if RTTIType = nil then
begin
raise EMVCDeserializationException. Create( 'Insufficient RTTI to deserialize record' ) ;
end ;
2022-05-25 15:13:49 +02:00
lTypeSize : = RTTIType. TypeSize;
2022-07-05 12:26:35 +02:00
GetMem( Buffer, lTypeSize) ;
FillChar( Buffer^ , lTypeSize, 0 ) ;
2022-08-08 17:51:21 +02:00
{$IF Defined(SYDNEYORBETTER)}
2022-07-26 17:04:39 +02:00
InvokeRecordInitializer( Buffer, RTTIType. Handle) ;
2022-07-26 09:31:26 +02:00
{$ENDIF}
2022-07-05 14:42:41 +02:00
lField : = nil ;
2022-05-25 15:13:49 +02:00
AIgnoredAttributes : = [ ] ;
2022-07-05 12:26:35 +02:00
try
for lField in RTTIType. GetFields do
if ( not TMVCSerializerHelper. HasAttribute< MVCDoNotDeserializeAttribute> ( lField) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, lField. Name ) ) then
2022-05-25 15:13:49 +02:00
begin
2022-07-05 12:26:35 +02:00
lKeyName : = TMVCSerializerHelper. GetKeyName( lField, RTTIType) ;
if lField. FieldType. IsRecord then
begin
JSONObjectToNestedRecordField( JSONObject. O[ lKeyName] , lField, 0 , Buffer) ;
end
else
begin
lAttributeValue : = lField. GetValue( Buffer) ;
2022-08-01 19:11:42 +02:00
JSONObjectPropertyToTValueForRecord( JSONObject, lKeyName, TMVCSerializationType. stProperties,
AIgnoredAttributes, lAttributeValue, lField. GetAttributes, lField) ;
2022-07-05 12:26:35 +02:00
lField. SetValue( Buffer, lAttributeValue) ;
2022-05-25 15:13:49 +02:00
end ;
end ;
2022-07-05 12:26:35 +02:00
except
on E: EInvalidCast do
begin
if lField < > nil then
2022-05-25 15:13:49 +02:00
begin
2022-07-05 12:26:35 +02:00
lErrMsg : = Format( 'Invalid class typecast for field "%s" [Expected: %s, Actual: %s]' ,
[ lKeyName, lField. FieldType. ToString( ) , JDO_TYPE_DESC[ JSONObject[ lKeyName] . Typ] ] ) ;
end
else
begin
lErrMsg : = Format( 'Invalid class typecast for field "%s" [Actual: %s]' ,
[ lKeyName, JDO_TYPE_DESC[ JSONObject[ lKeyName] . Typ] ] ) ;
2022-05-25 15:13:49 +02:00
end ;
2022-07-05 12:26:35 +02:00
raise EMVCException. Create( HTTP_STATUS. BadRequest, lErrMsg) ;
end ;
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. JSONObjectToRecordStatic( const JSONObject: TJsonObject;
RTTIType: TRttiRecordType; var Buffer: PByte ) ;
2022-07-10 23:30:00 +02:00
var
lTypeSize: Integer ;
AIgnoredAttributes: TMVCIgnoredList;
lKeyName: string ;
lAttributeValue: TValue;
lErrMsg: string ;
2022-08-01 19:11:42 +02:00
lField: TRttiField;
2022-07-10 23:30:00 +02:00
begin
lTypeSize : = RTTIType. TypeSize;
GetMem( Buffer, lTypeSize) ;
FillChar( Buffer^ , lTypeSize, 0 ) ;
2022-08-09 12:20:50 +02:00
{$IF Defined(SYDNEYORBETTER)}
2022-07-26 17:04:39 +02:00
InvokeRecordInitializer( Buffer, RTTIType. Handle) ;
2022-07-26 09:31:26 +02:00
{$ENDIF}
2022-07-10 23:30:00 +02:00
lField : = nil ;
AIgnoredAttributes : = [ ] ;
try
for lField in RTTIType. GetFields do
if ( not TMVCSerializerHelper. HasAttribute< MVCDoNotDeserializeAttribute> ( lField) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, lField. Name ) ) then
begin
lKeyName : = TMVCSerializerHelper. GetKeyName( lField, RTTIType) ;
if lField. FieldType. IsRecord then
begin
JSONObjectToNestedRecordField( JSONObject. O[ lKeyName] , lField, 0 , Buffer) ;
end
else
begin
lAttributeValue : = lField. GetValue( Buffer) ;
2022-08-01 19:11:42 +02:00
JSONObjectPropertyToTValueForRecord( JSONObject, lKeyName, TMVCSerializationType. stProperties,
AIgnoredAttributes, lAttributeValue, lField. GetAttributes, lField) ;
2022-07-10 23:30:00 +02:00
lField. SetValue( Buffer, lAttributeValue) ;
end ;
end ;
except
on E: EInvalidCast do
begin
if lField < > nil then
2017-03-01 21:40:57 +01:00
begin
2022-07-10 23:30:00 +02:00
lErrMsg : = Format( 'Invalid class typecast for field "%s" [Expected: %s, Actual: %s]' ,
[ lKeyName, lField. FieldType. ToString( ) , JDO_TYPE_DESC[ JSONObject[ lKeyName] . Typ] ] ) ;
end
else
begin
lErrMsg : = Format( 'Invalid class typecast for field "%s" [Actual: %s]' ,
[ lKeyName, JDO_TYPE_DESC[ JSONObject[ lKeyName] . Typ] ] ) ;
2017-03-01 21:40:57 +01:00
end ;
2022-07-10 23:30:00 +02:00
raise EMVCException. Create( HTTP_STATUS. BadRequest, lErrMsg) ;
end ;
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. JSONObjectToNestedRecordField( const JSONObject: TJsonObject;
RecordFieldRTTIType: TRttiField; const TypeOffset: Integer ; var Buffer: PByte ) ;
2022-07-05 12:26:35 +02:00
var
lChildType: TRttiType;
lChildFieldOffset: Integer ;
lKeyName: String ;
2022-07-05 13:20:09 +02:00
lValue: TValue;
2022-07-11 00:09:59 +02:00
lField: TRttiField;
2022-07-05 12:26:35 +02:00
begin
if RecordFieldRTTIType. FieldType. TypeKind < > tkRecord then
begin
raise EMVCDeserializationException. Create( 'Only record type allowed' ) ;
end ;
2022-08-01 19:11:42 +02:00
lChildType : = RecordFieldRTTIType. FieldType;
2022-07-05 12:26:35 +02:00
lChildFieldOffset : = RecordFieldRTTIType. Offset + TypeOffset;
2022-07-11 00:09:59 +02:00
for lField in lChildType. GetFields do
2022-07-05 12:26:35 +02:00
begin
2022-07-05 13:20:09 +02:00
lKeyName : = TMVCSerializerHelper. GetKeyName( lField, lChildType) ;
lValue : = lField. GetValue( Buffer + lChildFieldOffset) ;
2022-07-07 15:09:31 +02:00
JSONObjectPropertyToTValueForRecord( JSONObject, lKeyName, stFields, nil , lValue, nil , lField) ;
2022-07-05 13:20:09 +02:00
lField. SetValue( Buffer + lChildFieldOffset, lValue) ;
2022-05-25 15:13:49 +02:00
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. JSONObjectToNestedRecordFieldStatic( const JSONObject: TJsonObject;
RecordFieldRTTIType: TRttiField; const TypeOffset: Integer ; var Buffer: PByte ) ;
2022-07-07 15:09:31 +02:00
var
lChildType: TRttiType;
lKeyName: String ;
lValue: TValue;
2022-07-11 00:09:59 +02:00
lField: TRttiField;
2022-07-07 15:09:31 +02:00
begin
if RecordFieldRTTIType. FieldType. TypeKind < > tkRecord then
begin
raise EMVCDeserializationException. Create( 'Only record type allowed' ) ;
end ;
2022-08-01 19:11:42 +02:00
// Recupero il tipo e l'offset
lChildType : = RecordFieldRTTIType. FieldType;
// lChildFieldOffset := RecordFieldRTTIType.Offset + TypeOffset;
2022-07-07 15:09:31 +02:00
2022-08-01 19:11:42 +02:00
// recupero i campi
2022-07-11 00:09:59 +02:00
for lField in lChildType. GetFields do
2022-07-07 15:09:31 +02:00
begin
lKeyName : = TMVCSerializerHelper. GetKeyName( lField, lChildType) ;
lValue : = lField. GetValue( Buffer) ; // + lChildFieldOffset);
JSONObjectPropertyToTValueForRecord( JSONObject, lKeyName, stFields, nil , lValue, nil , lField) ;
2022-08-01 19:11:42 +02:00
lField. SetValue( Buffer { + lChildFieldOffset } , lValue) ;
2017-03-01 21:40:57 +01:00
end ;
end ;
2021-01-27 20:25:35 +01: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;
2020-09-22 15:18:22 +02:00
lJsonDataType: TJsonDataType;
lJSONValue: TJsonBaseObject;
2018-10-23 16:18:34 +02:00
begin
if not Assigned( AList) then
2022-07-23 01:21:52 +02:00
begin
2018-10-23 16:18:34 +02:00
raise EMVCSerializationException. Create( 'List not assigned' ) ;
2022-07-23 01:21:52 +02:00
end ;
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
2021-01-27 20:25:35 +01:00
lJSONValue : = ConvertObjectToJsonValue( AList. GetItem( I) , AType, AIgnoredAttributes, nil , ASerializationAction,
lJsonDataType) ;
2020-09-22 15:18:22 +02:00
case lJsonDataType of
jdtArray:
begin
AJsonArray. Add( lJSONValue as TJsonArray) ;
end ;
jdtObject:
begin
AJsonArray. Add( lJSONValue as TJsonObject) ;
end ;
else
begin
lJSONValue. Free;
2022-08-01 19:11:42 +02:00
RaiseSerializationError( 'Invalid JSON Data Type: ' + GetEnumName( TypeInfo( TJsonDataType) ,
Ord( lJsonDataType) ) ) ;
2020-09-22 15:18:22 +02:00
end
end ;
2019-03-08 09:33:41 +01:00
end ;
2018-10-23 16:18:34 +02:00
end ;
end ;
2022-08-01 19:11:42 +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
2022-08-01 19:11:42 +02:00
InternalObjectToJsonObject( AObject, AJSONObject, AType, AIgnoredAttributes, nil , nil , nil ) ;
2019-03-08 09:33:41 +01:00
end ;
2022-08-28 13:06:16 +02:00
procedure TMVCJsonDataObjectsSerializer. InternalObjectToJsonObject(
const AObject: TObject;
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 }
2020-09-11 13:01:56 +02:00
if AObject = nil then
begin
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
for Prop in ObjType. GetProperties do
2017-05-25 12:30:08 +02:00
begin
2024-06-08 23:05:46 +02:00
if TMVCSerializerHelper. IsAPropertyToSkip( Prop. Name ) then
begin
Continue;
end ;
// if Prop.Name = 'RefCount' then
// begin
// Continue;
// end;
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-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
2022-08-01 19:11:42 +02:00
TValueToJSONObjectProperty( 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
2022-08-01 19:11:42 +02:00
TValueToJSONObjectProperty( AJSONObject, TMVCSerializerHelper. GetKeyName( Fld, ObjType) ,
2021-01-27 20:25:35 +01:00
Fld. GetValue( AObject) , 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) ;
2022-08-01 19:11:42 +02:00
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 ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. InternalRecordToJsonObject( const ARecord: Pointer ;
const ARecordTypeInfo: PTypeInfo; const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType;
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction;
const Links: IMVCLinks; const Serializer: IMVCTypeSerializer) ;
2022-07-05 13:20:09 +02:00
var
ObjType: TRttiType;
Prop: TRttiProperty;
Fld: TRttiField;
lKeyName: String ;
begin
{ TODO -oDanieleT -cGeneral : Find a way to automatically add HATEOS }
if ARecord = nil then
begin
Exit;
end ;
ObjType : = GetRttiContext. GetType( ARecordTypeInfo) ;
case AType of
stDefault, stProperties:
begin
for Prop in ObjType. GetProperties do
begin
{$IFDEF AUTOREFCOUNT}
if TMVCSerializerHelper. IsAPropertyToSkip( Prop. Name ) then
continue;
{$ENDIF}
if ( not TMVCSerializerHelper. HasAttribute< MVCDoNotSerializeAttribute> ( Prop) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, Prop. Name ) ) then
2022-08-01 19:11:42 +02:00
TValueToJSONObjectProperty( AJSONObject, TMVCSerializerHelper. GetKeyName( Prop, ObjType) ,
2022-07-05 13:20:09 +02:00
Prop. GetValue( ARecord) , AType, AIgnoredAttributes, Prop. GetAttributes) ;
end ;
end ;
stFields:
begin
2022-07-25 15:32:31 +02:00
try
for Fld in ObjType. GetFields do
begin
if ( not TMVCSerializerHelper. HasAttribute< MVCDoNotSerializeAttribute> ( Fld) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, Fld. Name ) ) then
2022-08-01 19:11:42 +02:00
begin
lKeyName : = TMVCSerializerHelper. GetKeyName( Fld, ObjType) ;
TValueToJSONObjectProperty( AJSONObject, lKeyName, Fld. GetValue( ARecord) , AType, AIgnoredAttributes,
Fld. GetAttributes) ;
end ;
2022-07-25 15:32:31 +02:00
end ;
except
on E: Exception do
begin
2022-08-01 19:11:42 +02:00
raise EMVCSerializationException. CreateFmt( 'Cannot serialize field [%s] - [CLS: %s][MSG: %s]' ,
[ lKeyName, E. ClassName, E. Message ] ) ;
2022-07-25 15:32:31 +02:00
end ;
2022-07-05 13:20:09 +02:00
end ;
end ;
end ;
end ;
2021-01-27 20:25:35 +01:00
procedure TMVCJsonDataObjectsSerializer. InternalSerializeDataSet( const ADataSet: TDataSet; const AJsonArray: TJsonArray;
const AIgnoredFields: TMVCIgnoredList; const ANameCase: TMVCNameCase;
2020-04-20 17:56:17 +02:00
const ASerializationAction: TMVCDatasetSerializationAction) ;
var
BookMark: TBookmark;
lLinks: IMVCLinks;
LJObj: TJsonObject;
lDataSetFields: TMVCDataSetFields;
begin
lLinks : = nil ;
if Assigned( ASerializationAction) then
begin
lLinks : = TJDOLinks. Create;
end ;
lDataSetFields : = GetDataSetFields( ADataSet, AIgnoredFields, ANameCase) ;
try
BookMark : = ADataSet. BookMark;
try
ADataSet. First;
while not ADataSet. Eof do
begin
LJObj : = AJsonArray. AddObject;
DataSetToJsonObject( ADataSet, LJObj, ncAsIs { already applied } , AIgnoredFields, lDataSetFields) ;
if Assigned( ASerializationAction) then
begin
lLinks. Clear;
ASerializationAction( ADataSet, lLinks) ;
TJDOLinks( lLinks) . FillJSONArray( LJObj. A[ TMVCConstants. HATEOAS_PROP_NAME] ) ;
end ;
ADataSet. Next;
end ;
finally
if ADataSet. BookmarkValid( BookMark) then
ADataSet. GotoBookmark( BookMark) ;
ADataSet. FreeBookmark( BookMark) ;
end ;
finally
lDataSetFields. Free;
end ;
end ;
2021-01-27 20:25:35 +01:00
procedure TMVCJsonDataObjectsSerializer. InternalSerializeDataSetRecord( const DataSet: TDataSet;
const JSONObject: TJsonObject; const IgnoredFields: TMVCIgnoredList; const NameCase: TMVCNameCase;
2020-04-21 17:04:04 +02:00
const SerializationAction: TMVCDatasetSerializationAction) ;
var
lNameCase: TMVCNameCase;
lDataSetFields: TList< TMVCDataSetField> ;
lLinks: IMVCLinks;
begin
lNameCase : = GetNameCase( DataSet, NameCase) ;
lDataSetFields : = GetDataSetFields( DataSet, IgnoredFields, lNameCase) ;
try
DataSetToJsonObject( DataSet, JSONObject, ncAsIs { lNameCase } , IgnoredFields, lDataSetFields) ;
lLinks : = TJDOLinks. Create;
if Assigned( SerializationAction) then
begin
SerializationAction( DataSet, lLinks) ;
2021-01-27 20:25:35 +01:00
TJDOLinks( lLinks) . FillJSONArray( JSONObject. A[ TMVCSerializerHelper. ApplyNameCase( lNameCase,
TMVCConstants. HATEOAS_PROP_NAME) ] ) ;
2020-04-21 17:04:04 +02:00
end ;
finally
lDataSetFields. Free;
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. InternalTValueToJsonObject( const AValue: TValue;
const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
const ASerializationAction: TMVCSerializationAction; const Links: IMVCLinks; const Serializer: IMVCTypeSerializer) ;
2022-05-25 15:13:49 +02:00
var
ObjType: TRttiType;
Prop: TRttiProperty;
Fld: TRttiField;
begin
if AValue. IsEmpty then
begin
Exit;
end ;
if AValue. TypeInfo. Kind < > tkRecord then
begin
raise EMVCSerializationException. Create( 'Expected Record' ) ;
end ;
ObjType : = GetRttiContext. GetType( AValue. TypeInfo) ;
case AType of
stDefault, stProperties:
begin
for Prop in ObjType. GetProperties do
begin
{$IFDEF AUTOREFCOUNT}
if TMVCSerializerHelper. IsAPropertyToSkip( Prop. Name ) then
continue;
{$ENDIF}
if ( not TMVCSerializerHelper. HasAttribute< MVCDoNotSerializeAttribute> ( Prop) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, Prop. Name ) ) then
2022-08-01 19:11:42 +02:00
TValueToJSONObjectProperty( AJSONObject, TMVCSerializerHelper. GetKeyName( Prop, ObjType) ,
2022-05-25 15:13:49 +02:00
Prop. GetValue( AValue. GetReferenceToRawData) , AType, AIgnoredAttributes, Prop. GetAttributes) ;
end ;
end ;
stFields:
begin
for Fld in ObjType. GetFields do
begin
if ( not TMVCSerializerHelper. HasAttribute< MVCDoNotSerializeAttribute> ( Fld) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, Fld. Name ) ) then
2022-08-01 19:11:42 +02:00
TValueToJSONObjectProperty( AJSONObject, TMVCSerializerHelper. GetKeyName( Fld, ObjType) ,
2022-05-25 15:13:49 +02:00
Fld. GetValue( AValue. GetReferenceToRawData) , AType, AIgnoredAttributes, Fld. GetAttributes) ;
end ;
end ;
end ;
2022-08-01 19:11:42 +02:00
// if Assigned(ASerializationAction) then
// begin
// ASerializationAction(AObject, Links);
// TJDOLinks(Links).FillJSONArray(AJsonObject.A[TMVCConstants.HATEOAS_PROP_NAME]);
// end;
2022-05-25 15:13:49 +02:00
end ;
2021-01-27 20:25:35 +01:00
class function TMVCJsonDataObjectsSerializer. Parse< T> ( const AString: string ) : T;
2018-10-23 16:18:34 +02:00
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 ;
2021-01-27 20:25:35 +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 ;
2021-01-27 20:25:35 +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 ;
2022-08-10 17:57:59 +02:00
procedure TMVCJsonDataObjectsSerializer. ParseStringAsTValueUsingMetadata(
const AStringValue: String ;
const DestinationTypeInfo: PTypeInfo;
const ExceptionHintString: String ;
const AAttributes: TArray< TCustomAttribute> ;
var AValue: TValue) ;
var
lValueTypeInfo: PTypeInfo;
2022-08-23 17:14:12 +02:00
lEnumSerType: TMVCEnumSerializationType;
lEnumAsAttr: MVCEnumSerializationAttribute;
lEnumMappedValues: TList< string > ;
lMappedValueIndex: Integer ;
2022-08-10 17:57:59 +02:00
lOutInteger: Integer ;
lOutInteger64: Int64 ;
lInt: Integer ;
begin
lValueTypeInfo : = DestinationTypeInfo;
if ( lValueTypeInfo = System. TypeInfo( TDate) ) then
AValue : = TValue. From< TDate> ( ISODateToDate( AStringValue) )
else if ( lValueTypeInfo = System. TypeInfo( TDateTime) ) then
AValue : = TValue. From< TDateTime> ( ISOTimeStampToDateTime( AStringValue) )
else if ( lValueTypeInfo = System. TypeInfo( TTime) ) then
AValue : = TValue. From< TTime> ( ISOTimeToTime( AStringValue) )
else if ( lValueTypeInfo. Kind = tkRecord) and ( lValueTypeInfo < > TypeInfo( TValue) ) then { nullables }
begin
if lValueTypeInfo = TypeInfo( NullableString) then
begin
AValue : = TValue. From< NullableString> ( NullableString( AStringValue) )
end
else if lValueTypeInfo = TypeInfo( NullableTDate) then
begin
AValue : = TValue. From< NullableTDate> ( NullableTDate( ISODateToDate( AStringValue) ) )
end
else if lValueTypeInfo = TypeInfo( NullableTDateTime) then
begin
AValue : = TValue. From< NullableTDateTime>
( NullableTDateTime( ISOTimeStampToDateTime( AStringValue) ) )
end
else if lValueTypeInfo = TypeInfo( NullableTTime) then
begin
AValue : = TValue. From< NullableTTime> ( NullableTTime( ISOTimeToTime( AStringValue) ) )
end
else if lValueTypeInfo = TypeInfo( NullableTGUID) then
begin
AValue : = TValue. From< NullableTGUID> ( TMVCGuidHelper. StringToGUIDEx( AStringValue) ) ;
end
2024-05-14 23:26:10 +02:00
else if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( AAttributes) then
begin
//the string must be converted to int using sqids
if lValueTypeInfo = TypeInfo( NullableInt16) then
AValue : = TValue. From< NullableInt16> ( TMVCSqids. SqidToInt( AStringValue) )
else if lValueTypeInfo = TypeInfo( NullableInt32) then
AValue : = TValue. From< NullableInt32> ( TMVCSqids. SqidToInt( AStringValue) )
else if lValueTypeInfo = TypeInfo( NullableInt64) then
AValue : = TValue. From< NullableInt64> ( TMVCSqids. SqidToInt( AStringValue) )
else
raise EMVCSerializationException. CreateFmt( 'Cannot deserialize Sqids "%s" from string to integer' , [ ExceptionHintString] ) ;
end
2022-08-10 17:57:59 +02:00
else
begin
raise EMVCSerializationException. CreateFmt( 'Cannot deserialize "%s" from string' , [ ExceptionHintString] ) ;
end ;
end
else if ( lValueTypeInfo. Kind = tkEnumeration) then
begin
2022-08-23 17:14:12 +02:00
lEnumSerType : = estEnumName;
lEnumMappedValues : = nil ;
if TMVCSerializerHelper. AttributeExists< MVCEnumSerializationAttribute> ( AAttributes, lEnumAsAttr) then
2022-08-10 17:57:59 +02:00
begin
2022-08-23 17:14:12 +02:00
lEnumSerType : = lEnumAsAttr. SerializationType;
lEnumMappedValues : = lEnumAsAttr. MappedValues;
2022-08-10 17:57:59 +02:00
end ;
2022-08-23 17:14:12 +02:00
if lEnumSerType = estEnumName then
2022-08-10 17:57:59 +02:00
begin
lOutInteger : = GetEnumValue( lValueTypeInfo, AStringValue) ;
if lOutInteger = - 1 then
begin
raise EMVCSerializationException. CreateFmt( 'Cannot deserialize "%s" from mapped values' ,
[ ExceptionHintString] ) ;
end ;
TValue. Make( lOutInteger, lValueTypeInfo, AValue)
end
else
begin
2022-08-23 17:14:12 +02:00
lMappedValueIndex : = lEnumMappedValues. IndexOf( AStringValue) ;
if lMappedValueIndex < 0 then
2022-08-10 17:57:59 +02:00
raise EMVCSerializationException. CreateFmt( 'Cannot deserialize "%s" from mapped values' ,
[ ExceptionHintString] ) ;
2022-08-23 17:14:12 +02:00
TValue. Make( GetEnumValue( lValueTypeInfo, GetEnumName( lValueTypeInfo, lMappedValueIndex) ) ,
2022-08-10 17:57:59 +02:00
lValueTypeInfo, AValue)
end ;
end
2024-05-14 23:44:08 +02:00
else if lValueTypeInfo. Kind = tkInteger then
2022-08-10 17:57:59 +02:00
begin
2024-05-14 23:44:08 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( AAttributes) then
lOutInteger : = TMVCSqids. SqidToInt( AStringValue)
else
lOutInteger : = StrToInt( AStringValue) ;
2022-08-10 17:57:59 +02:00
AValue : = lOutInteger;
end
2024-05-14 23:44:08 +02:00
else if lValueTypeInfo. Kind = tkInt64 then
2022-08-10 17:57:59 +02:00
begin
2024-05-14 23:44:08 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( AAttributes) then
lOutInteger64 : = TMVCSqids. SqidToInt( AStringValue)
else
lOutInteger64 : = StrToInt64( AStringValue) ;
2022-08-10 17:57:59 +02:00
AValue : = lOutInteger64;
end
else if lValueTypeInfo. Kind = tkSet then
begin
lInt : = StringToSet( lValueTypeInfo, StringReplace( AStringValue, ' ' , '' , [ rfReplaceAll] ) ) ;
TValue. Make( lInt, lValueTypeInfo, AValue) ;
end
else
begin
AValue : = TValue. From< string > ( AStringValue) ;
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure TMVCJsonDataObjectsSerializer. RecordToJsonObject( const ARecord: Pointer ; const ARecordTypeInfo: PTypeInfo;
const AJSONObject: TJDOJsonObject; const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList) ;
2022-07-05 13:20:09 +02:00
begin
2022-08-01 19:11:42 +02:00
InternalRecordToJsonObject( ARecord, ARecordTypeInfo, AJSONObject, AType, AIgnoredAttributes, nil , nil , nil ) ;
2022-07-05 13:20:09 +02:00
end ;
2021-01-27 20:25:35 +01:00
function TMVCJsonDataObjectsSerializer. SerializeCollection( const AList: TObject; const AType: TMVCSerializationType;
2019-10-24 15:34:40 +02:00
const AIgnoredAttributes: TMVCIgnoredList; const ASerializationAction: TMVCSerializationAction) : string ;
2017-03-01 21:40:57 +01:00
var
2022-08-01 19:11:42 +02: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;
2021-06-01 15:10:45 +02:00
lObjType: TRttiType;
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
2021-06-01 15:10:45 +02:00
lObjType : = GetRttiContext. GetType( AList. ClassType) ;
if GetTypeSerializers. ContainsKey( lObjType. Handle) then
begin
2022-08-01 19:11:42 +02:00
GetTypeSerializers. Items[ lObjType. Handle] . SerializeRoot( AList, TObject( JSONArray) , [ ] ) ;
2021-06-01 15:10:45 +02:00
try
2022-08-01 19:11:42 +02:00
Result : = JSONArray. ToJSON( True ) ;
2021-06-01 15:10:45 +02:00
finally
2022-08-01 19:11:42 +02:00
JSONArray. Free;
2021-06-01 15:10:45 +02:00
end ;
Exit;
end ;
2017-03-01 21:40:57 +01:00
ObjList : = TDuckTypedList. Wrap( AList) ;
if Assigned( ObjList) then
begin
2022-08-01 19:11:42 +02: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;
2022-08-01 19:11:42 +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
2021-01-27 20:25:35 +01:00
if Obj < > nil then
begin
2023-07-19 11:10:21 +02:00
if Obj is TDataSet then
begin
2024-06-08 23:05:46 +02:00
DataSetToJsonArray( TDataSet( Obj) , JSONArray. AddArray, TMVCNameCase. ncUseDefault, nil , nil , ) ;
2023-07-19 11:10:21 +02:00
end
else
begin
ObjectToJsonObject( Obj, JSONArray. AddObject, GetSerializationType( Obj, AType) , AIgnoredAttributes)
end ;
2021-01-27 20:25:35 +01:00
end
else
begin
2022-08-01 19:11:42 +02:00
JSONArray. Add( TJsonObject( nil ) ) ;
2021-01-27 20:25:35 +01:00
end ;
2018-12-12 11:00:41 +01:00
end ;
end ;
2022-08-01 19:11:42 +02:00
Result : = JSONArray. ToJSON( True ) ;
2017-03-01 21:40:57 +01:00
finally
2022-08-01 19:11:42 +02:00
JSONArray. Free;
2017-03-01 21:40:57 +01:00
end ;
end ;
end ;
2023-03-14 08:56:00 +01:00
function TMVCJsonDataObjectsSerializer. SerializeArrayOfRecord(
var ATValueContainingAnArray: TValue; const AType: TMVCSerializationType;
const AIgnoredAttributes: TMVCIgnoredList;
const ASerializationAction: TMVCSerializationAction) : string ;
var
I: Integer ;
lCurrentArrayItem: TValue;
lJSONArr: TJsonArray;
lJObj: TJsonObject;
begin
if not ATValueContainingAnArray. IsArray then
begin
raise EMVCSerializationException. Create( String( ATValueContainingAnArray. TypeInfo^ . Name ) + ' is not an array' ) ;
end ;
if ATValueContainingAnArray. GetArrayLength = 0 then
begin
Result : = '[]' ;
end ;
lJSONArr : = TJsonArray. Create;
try
for I : = 0 to ATValueContainingAnArray. GetArrayLength - 1 do
begin
lJObj : = lJSONArr. AddObject;
lCurrentArrayItem : = ATValueContainingAnArray. GetArrayElement( I) ;
2023-07-19 11:10:21 +02:00
if lCurrentArrayItem. IsObjectInstance then
begin
raise EMVCSerializationException. CreateFmt( 'Found a "%s" while serializing array. Instance types not allowed in arrays - [HINT] Use list of objects instead of array' , [ lCurrentArrayItem. AsObject. ClassName] ) ;
end
else
begin
InternalRecordToJsonObject(
lCurrentArrayItem. GetReferenceToRawData,
lCurrentArrayItem. TypeInfo,
lJObj,
TMVCSerializationType. stFields,
nil ,
nil ,
nil ,
nil
) ;
end ;
2023-03-14 08:56:00 +01:00
end ;
Result : = lJSONArr. ToJSON( ) ;
finally
lJSONArr. free;
end ;
end ;
2021-01-27 20:25:35 +01:00
function TMVCJsonDataObjectsSerializer. SerializeCollection( const AList: IInterface; const AType: TMVCSerializationType;
2019-09-18 01:14:54 +02:00
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 ;
2021-01-27 20:25:35 +01:00
function TMVCJsonDataObjectsSerializer. SerializeDataSet( const ADataSet: TDataSet; const AIgnoredFields: TMVCIgnoredList;
2021-03-03 23:16:55 +01:00
const ANameCase: TMVCNameCase; const ASerializationAction: TMVCDatasetSerializationAction) : string ;
2017-03-29 14:49:35 +02:00
var
2022-08-01 19:11:42 +02:00
JSONArray: TJDOJsonArray;
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
2022-08-01 19:11:42 +02:00
JSONArray : = TJsonArray. Create;
2017-03-29 14:49:35 +02:00
try
2022-08-01 19:11:42 +02:00
InternalSerializeDataSet( ADataSet, JSONArray, AIgnoredFields, ANameCase, ASerializationAction) ;
Result : = JSONArray. ToJSON( True ) ;
2017-03-29 14:49:35 +02:00
finally
2022-08-01 19:11:42 +02:00
JSONArray. Free;
2017-03-29 14:49:35 +02:00
end ;
2017-03-01 21:40:57 +01:00
end ;
2020-04-21 17:04:04 +02:00
function TMVCJsonDataObjectsSerializer. SerializeDataSetRecord( const DataSet: TDataSet;
2020-05-19 00:49:34 +02:00
const IgnoredFields: TMVCIgnoredList; const NameCase: TMVCNameCase = ncAsIs;
2020-04-21 17:04:04 +02:00
const SerializationAction: TMVCDatasetSerializationAction = nil ) : string ;
2017-03-29 14:49:35 +02:00
var
2020-04-21 17:04:04 +02:00
lJSONObject: TJDOJsonObject;
2017-03-13 20:52:11 +01:00
begin
2020-02-03 10:51:40 +01:00
Result : = EmptyStr;
2020-04-21 17:04:04 +02:00
if ( not Assigned( DataSet) ) or DataSet. IsEmpty then
2019-05-19 11:06:03 +02:00
Exit( 'null' ) ;
2020-04-21 17:04:04 +02:00
lJSONObject : = TJDOJsonObject. Create;
2017-03-29 14:49:35 +02:00
try
2020-04-21 17:04:04 +02:00
InternalSerializeDataSetRecord( DataSet, lJSONObject, IgnoredFields, NameCase, SerializationAction) ;
Result : = lJSONObject. ToJSON( True ) ;
2017-03-29 14:49:35 +02:00
finally
2020-04-21 17:04:04 +02:00
lJSONObject. Free;
2017-03-29 14:49:35 +02:00
end ;
2017-03-13 20:52:11 +01:00
end ;
2021-01-27 20:25:35 +01:00
function TMVCJsonDataObjectsSerializer. SerializeObject( const AObject: TObject; const AType: TMVCSerializationType;
2019-10-24 15:34:40 +02:00
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
2020-05-19 00:49:34 +02:00
Exit( self. SerializeDataSet( TDataSet( AObject) , AIgnoredAttributes) ) ;
2018-07-16 12:34:07 +02:00
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 ;
2021-01-27 20:25:35 +01:00
function TMVCJsonDataObjectsSerializer. SerializeObject( const AObject: IInterface; const AType: TMVCSerializationType;
2019-09-18 01:14:54 +02:00
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');
2021-01-27 20:25:35 +01:00
Result : = SerializeObject( TObject( AObject) , AType, TMVCIgnoredList( LIgnoredAttrs. ToArray) , ASerializationAction) ;
2019-09-18 01:14:54 +02:00
finally
LIgnoredAttrs. Free;
end ;
end ;
2021-01-27 20:25:35 +01: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
2020-04-21 17:04:04 +02: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
2020-04-21 17:04:04 +02:00
GetTypeSerializers. Items[ ObjType. Handle] . SerializeRoot( AObject, TObject( JSONObject) , [ ] ) ;
2018-12-12 11:00:41 +01:00
try
2020-04-21 17:04:04 +02:00
Result : = JSONObject;
2018-12-12 11:00:41 +01:00
except
2020-04-21 17:04:04 +02:00
JSONObject. Free;
2018-12-12 11:00:41 +01:00
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 ;
2022-08-01 19:11:42 +02:00
function TMVCJsonDataObjectsSerializer. SerializeRecord( const ARecord: Pointer ; const ARecordTypeInfo: PTypeInfo;
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList;
2022-07-05 13:20:09 +02:00
const ASerializationAction: TMVCSerializationAction) : string ;
2022-07-18 18:04:36 +02:00
var
lJSON: TJDOJsonObject;
2022-07-05 13:20:09 +02:00
begin
2022-07-18 18:04:36 +02:00
lJSON : = TJDOJsonObject. Create;
try
2022-08-01 19:11:42 +02:00
RecordToJsonObject( ARecord, ARecordTypeInfo, lJSON, TMVCSerializationType. stFields, nil ) ;
2022-07-18 18:04:36 +02:00
Result : = lJSON. ToJSON( True ) ;
finally
lJSON. Free;
end ;
2022-07-05 13:20:09 +02:00
end ;
2021-01-27 20:25:35 +01:00
function TMVCJsonDataObjectsSerializer. TryMapNullableFloat( var Value: TValue; const JSONDataObject: TJsonObject;
const AttribName: string ) : Boolean ;
2020-04-18 23:32:24 +02:00
begin
Result : = True ;
if Value. TypeInfo = TypeInfo( NullableSingle) then
Value : = TValue. From< NullableSingle> ( NullableSingle( JSONDataObject[ AttribName] . FloatValue) )
else if Value. TypeInfo = TypeInfo( NullableCurrency) then
Value : = TValue. From< NullableCurrency> ( NullableCurrency( JSONDataObject[ AttribName] . FloatValue) )
else if Value. TypeInfo = TypeInfo( NullableDouble) then
Value : = TValue. From< NullableDouble> ( NullableDouble( JSONDataObject[ AttribName] . FloatValue) )
else if Value. TypeInfo = TypeInfo( NullableExtended) then
Value : = TValue. From< NullableExtended> ( NullableExtended( JSONDataObject[ AttribName] . FloatValue) )
else
Result : = False ;
end ;
2022-08-01 19:11:42 +02:00
function TMVCJsonDataObjectsSerializer. TryNullableToJSON( const AValue: TValue; const AJSONObject: TJDOJsonObject;
2022-06-24 19:50:23 +02:00
const AName: string ; const ACustomAttributes: TArray< TCustomAttribute> ) : Boolean ;
2023-01-28 23:31:00 +01:00
var
lFoundANullable: Boolean ;
2020-02-03 10:51:40 +01:00
begin
Result : = False ;
2023-01-28 23:31:00 +01:00
lFoundANullable : = False ;
2020-02-03 10:51:40 +01:00
if ( AValue. TypeInfo = System. TypeInfo( NullableString) ) then
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableString> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = AValue. AsType< NullableString> ( ) . Value;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableInt32) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableInt32> ( ) . HasValue then
begin
2024-05-10 16:16:47 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( ACustomAttributes) then
begin
AJSONObject. S[ AName] : = TMVCSqids. IntToSqid( AValue. AsType< NullableInt32> ( ) . Value) ;
end
else
begin
AJSONObject. I[ AName] : = AValue. AsType< NullableInt32> ( ) . Value;
end ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableInt64) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableInt64> ( ) . HasValue then
begin
2024-05-10 16:16:47 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( ACustomAttributes) then
begin
AJSONObject. S[ AName] : = TMVCSqids. IntToSqid( AValue. AsType< NullableInt64> ( ) . Value) ;
end
else
begin
AJSONObject. L[ AName] : = AValue. AsType< NullableInt64> ( ) . Value;
end ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableInt16) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableInt16> ( ) . HasValue then
begin
2024-05-10 16:16:47 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( ACustomAttributes) then
begin
AJSONObject. S[ AName] : = TMVCSqids. IntToSqid( AValue. AsType< NullableInt16> ( ) . Value) ;
end
else
begin
AJSONObject. I[ AName] : = AValue. AsType< NullableInt16> ( ) . Value;
end ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableTDate) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableTDate> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = DateToISODate( AValue. AsType< NullableTDate> ( ) . Value) ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableTDateTime) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableTDateTime> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = DateTimeToISOTimeStamp( AValue. AsType< NullableTDateTime> ( ) . Value) ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableTTime) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableTTime> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = TimeToISOTime( AValue. AsType< NullableTTime> ( ) . Value) ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableBoolean) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableBoolean> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. B[ AName] : = AValue. AsType< NullableBoolean> ( ) . Value;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableCurrency) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableCurrency> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. F[ AName] : = AValue. AsType< NullableCurrency> ( ) . Value;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableSingle) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableSingle> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. F[ AName] : = AValue. AsType< NullableSingle> ( ) . Value;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableDouble) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableDouble> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. F[ AName] : = AValue. AsType< NullableDouble> ( ) . Value;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableExtended) ) then
2020-02-03 10:51:40 +01:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-02-03 10:51:40 +01:00
if AValue. AsType< NullableExtended> ( ) . HasValue then
begin
2022-08-01 19:11:42 +02:00
AJSONObject. F[ AName] : = AValue. AsType< NullableExtended> ( ) . Value;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-02-03 10:51:40 +01:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableUInt16) ) then { from here all nullable integers }
2020-04-18 15:04:27 +02:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-04-18 15:04:27 +02:00
if AValue. AsType< NullableUInt16> ( ) . HasValue then
begin
2024-05-10 16:16:47 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( ACustomAttributes) then
begin
AJSONObject. S[ AName] : = TMVCSqids. IntToSqid( AValue. AsType< NullableUInt16> ( ) . Value) ;
end
else
begin
AJSONObject. I[ AName] : = AValue. AsType< NullableUInt16> ( ) . Value;
end ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-04-18 15:04:27 +02:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableUInt32) ) then
2020-04-18 15:04:27 +02:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-04-18 15:04:27 +02:00
if AValue. AsType< NullableUInt32> ( ) . HasValue then
begin
2024-05-10 16:16:47 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( ACustomAttributes) then
begin
AJSONObject. S[ AName] : = TMVCSqids. IntToSqid( AValue. AsType< NullableUInt32> ( ) . Value) ;
end
else
begin
AJSONObject. I[ AName] : = AValue. AsType< NullableUInt32> ( ) . Value;
end ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-04-18 15:04:27 +02:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableUInt64) ) then
2020-04-18 15:04:27 +02:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2020-04-18 15:04:27 +02:00
if AValue. AsType< NullableUInt64> ( ) . HasValue then
begin
2024-05-10 16:16:47 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeAsSqidsAttribute> ( ACustomAttributes) then
begin
AJSONObject. S[ AName] : = TMVCSqids. IntToSqid( AValue. AsType< NullableUInt64> ( ) . Value) ;
end
else
begin
AJSONObject. I[ AName] : = AValue. AsType< NullableUInt64> ( ) . Value;
end ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2020-04-18 15:04:27 +02:00
end ;
2023-01-28 23:31:00 +01:00
end else if ( AValue. TypeInfo = System. TypeInfo( NullableTGUID) ) then
2022-06-23 14:34:01 +02:00
begin
2023-01-28 23:31:00 +01:00
lFoundANullable : = True ;
2022-06-23 14:34:01 +02:00
if AValue. AsType< NullableTGUID> ( ) . HasValue then
begin
2022-06-24 19:50:23 +02:00
if TMVCSerializerHelper. AttributeExists< MVCSerializeGuidWithoutBracesAttribute> ( ACustomAttributes) then
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = TMVCGuidHelper. GUIDToStringEx( AValue. AsType< NullableTGUID> ( ) . Value)
2022-06-24 19:50:23 +02:00
else
2022-08-01 19:11:42 +02:00
AJSONObject. S[ AName] : = GUIDToString( AValue. AsType< NullableTGUID> ( ) . Value) ;
2023-01-28 23:31:00 +01:00
Result : = True ;
2022-06-23 14:34:01 +02:00
end ;
end ;
2023-01-28 23:31:00 +01:00
{ if the type is a nullable but doesn't contains a value... }
if lFoundANullable and ( not Result ) and MVCSerializeNulls then
begin
AJSONObject. Values[ AName] : = nil ;
end ;
{ if MVCSerializeEmptyNullableAsNull = False, an empty nullable doesn't have to contains "null"}
Result : = lFoundANullable; {caller needs to know if AJSONObject contains a valid data}
2020-02-03 10:51:40 +01:00
end ;
2021-01-27 20:25:35 +01:00
procedure TMVCJsonDataObjectsSerializer. DeserializeObject( const ASerializedObject: string ; const AObject: TObject;
2020-08-13 17:40:02 +02:00
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList; const ARootNode: string ) ;
2017-03-01 21:40:57 +01:00
var
2020-04-21 17:04:04 +02:00
JSONObject: TJDOJsonObject;
2024-06-10 00:18:02 +02:00
JSONBase: TJsonBaseObject;
2017-03-01 21:40:57 +01:00
begin
if ( ASerializedObject = EmptyStr) then
2020-04-09 17:01:33 +02:00
raise EMVCException. Create( HTTP_STATUS. BadRequest, 'Invalid body' ) ;
2017-03-01 21:40:57 +01:00
if not Assigned( AObject) then
Exit;
try
2024-06-10 00:18:02 +02:00
JSONBase : = TJDOJsonObject. Parse( ASerializedObject) ;
try
if not( JSONBase is TJDOJsonObject) then
begin
raise EMVCSerializationException. CreateFmt( 'Invalid JSON. Expected %s got %s' ,
[ TJDOJsonObject. ClassName, JSONBase. ClassName] ) ;
end ;
JSONObject : = TJDOJsonObject( JSONBase) ;
if GetTypeSerializers. ContainsKey( AObject. ClassInfo) then
begin
GetTypeSerializers. Items[ AObject. ClassInfo] . DeserializeRoot( SelectRootNodeOrWholeObject( ARootNode, JSONObject) ,
AObject, [ ] )
end
else
begin
JsonObjectToObject( SelectRootNodeOrWholeObject( ARootNode, JSONObject) , AObject,
GetSerializationType( AObject, AType) , AIgnoredAttributes) ;
end ;
finally
JSONBase. Free;
2019-03-05 20:55:37 +01:00
end ;
2018-10-31 01:07:23 +01:00
except
on E: EJsonParserException do
2017-03-01 21:40:57 +01:00
begin
2020-04-09 17:01:33 +02:00
raise EMVCException. Create( HTTP_STATUS. BadRequest, E. Message ) ;
2018-10-31 01:07:23 +01:00
end ;
end ;
2017-03-01 21:40:57 +01:00
end ;
2021-01-27 20:25:35 +01: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
2020-04-09 17:01:33 +02:00
begin
2020-04-20 17:56:17 +02:00
{ gets the name as defined by NameAs attribute }
2019-10-24 15:34:40 +02:00
lField. FieldName : = GetNameAs( ADataSet. Owner, ADataSet. Fields[ I] . Name , ADataSet. Fields[ I] . FieldName) ;
2020-04-20 17:56:17 +02:00
{ apply the name case to the field name }
lField. FieldName : = TMVCSerializerHelper. ApplyNameCase( ANameCase, lField. FieldName) ;
2019-04-16 23:12:19 +02:00
lField. DataType : = ADataSet. Fields[ I] . DataType;
lField. I : = I;
2020-04-20 17:56:17 +02:00
if ( not IsIgnoredAttribute( AIgnoredFields, ADataSet. Fields[ I] . FieldName) ) and
2019-04-16 23:12:19 +02:00
( not IsIgnoredComponent( ADataSet. Owner, ADataSet. Fields[ I] . Name ) ) then
2020-02-03 10:51:40 +01:00
Result . Add( lField) ;
2020-04-09 17:01:33 +02:00
end ;
2019-04-16 23:12:19 +02:00
end ;
2020-09-11 13:37:45 +02:00
procedure TMVCJsonDataObjectsSerializer. AddTValueToJsonArray( const Value: TValue; const JSON: TJDOJsonArray) ;
2020-08-25 17:19:28 +02:00
var
lOrdinalValue: Int64 ;
lValueAsObj: TObject;
2020-09-11 13:37:45 +02:00
lTypeName: string ;
lJSONValue: TJsonBaseObject;
lJsonDataType: TJsonDataType;
2020-08-25 17:19:28 +02:00
begin
if Value. IsEmpty then
begin
JSON. Add( TJsonObject( nil ) ) ;
Exit;
end ;
case Value. Kind of
tkInteger:
begin
JSON. Add( Value. AsInteger) ;
end ;
tkFloat:
begin
{$IFDEF NEXTGEN}
2020-09-15 14:16:58 +02:00
lTypeName : = PChar( Pointer( Value. TypeInfo. Name ) ) ;
2020-08-25 17:19:28 +02:00
{$ELSE}
lTypeName : = string( Value. TypeInfo. Name ) ;
{$ENDIF}
if ( lTypeName = 'TDate' ) or ( lTypeName = 'TDateTime' ) or ( lTypeName = 'TTime' ) then
begin
JSON. Add( DateTimeToISOTimeStamp( Value. AsExtended) ) ;
end
else
begin
JSON. Add( Value. AsExtended) ;
end ;
end ;
tkString, tkUString, tkWChar, tkLString, tkWString:
begin
JSON. Add( Value. AsString) ;
end ;
tkInt64:
begin
JSON. Add( Value. AsInt64) ;
end ;
tkEnumeration:
begin
if ( Value. TypeInfo = System. TypeInfo( Boolean ) ) then
begin
JSON. Add( Value. AsBoolean) ;
end
else
begin
Value. TryAsOrdinal( lOrdinalValue) ;
JSON. Add( lOrdinalValue) ;
end ;
end ;
tkClass, tkInterface:
begin
if Value. Kind = tkInterface then
lValueAsObj : = TObject( Value. AsInterface)
else
lValueAsObj : = Value. AsObject;
2020-09-11 13:37:45 +02:00
2021-01-27 20:25:35 +01:00
lJSONValue : = ConvertObjectToJsonValue( lValueAsObj, GetSerializationType( lValueAsObj) , [ ] , nil , nil ,
lJsonDataType) ;
2020-09-11 13:37:45 +02:00
case lJsonDataType of
jdtArray:
begin
JSON. Add( TJsonArray( lJSONValue) ) ;
end ;
jdtObject:
begin
JSON. Add( TJsonObject( lJSONValue) ) ;
end ;
2020-08-25 17:19:28 +02:00
else
2020-09-11 13:37:45 +02:00
begin
lJSONValue. Free;
RaiseSerializationError( 'Invalid JSON Type' )
2020-08-25 17:19:28 +02:00
end ;
end ;
end ;
else
raise EMVCException. Create( 'Invalid type' ) ;
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure TValueToJSONObjectPropertyEx( 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;
2020-07-29 00:11:10 +02:00
lValueAsObjQualifClassName, lTypeName: 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}
2020-09-15 14:16:58 +02:00
lTypeName : = PChar( Pointer( Value. TypeInfo. Name ) ) ;
2019-03-05 20:55:37 +01:00
{$ELSE}
2020-08-06 17:40:56 +02:00
lTypeName : = string( Value. TypeInfo. Name ) ;
2019-03-05 20:55:37 +01:00
{$ENDIF}
2020-08-06 17:40:56 +02:00
if ( lTypeName = 'TDate' ) or ( lTypeName = 'TDateTime' ) or ( lTypeName = 'TTime' ) then
2018-12-12 14:48:35 +01:00
begin
2020-07-29 00:11:10 +02:00
JSON. D[ KeyName] : = Value. AsExtended;
2018-12-12 14:48:35 +01:00
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
2020-08-06 17:40:56 +02:00
if ( Value. TypeInfo = System. TypeInfo( Boolean ) ) then
begin
JSON. B[ KeyName] : = Value. AsBoolean;
end
else
begin
Value. TryAsOrdinal( lOrdinalValue) ;
JSON. I[ KeyName] : = lOrdinalValue;
end ;
2019-01-08 12:48:27 +01:00
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;
2024-06-08 23:05:46 +02:00
lSer. DataSetToJsonArray( TDataSet( lValueAsObj) , JSON. A[ KeyName] , TMVCNameCase. ncUseDefault, [ ] ) ;
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 ;
2021-04-06 19:21:53 +02:00
function StrToJSONObject( const AValue: string ; ARaiseExceptionOnError: Boolean ) : 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;
2021-04-06 19:21:53 +02:00
if ARaiseExceptionOnError and ( lJSON = nil ) then
begin
raise EMVCException. Create( 'Invalid JSON' ) ;
end ;
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;
2023-06-21 12:56:21 +02:00
Result : = nil ;
if ARaiseExceptionOnError then
begin
raise EMVCDeserializationException. Create( 'Invalid JSON Object - ' + E. Message ) ;
end ;
2020-06-24 00:00:47 +02:00
end ;
end ;
end ;
2021-04-06 19:21:53 +02:00
function StrToJSONArray( const AValue: string ; ARaiseExceptionOnError: Boolean ) : TJDOJsonArray;
2020-06-24 00:00:47 +02:00
var
lJSON: TJDOJsonArray;
begin
lJSON : = nil ;
try
lJSON : = TJDOJsonObject. Parse( AValue) as TJDOJsonArray;
2021-04-06 19:21:53 +02:00
if ARaiseExceptionOnError and ( lJSON = nil ) then
begin
raise EMVCException. Create( 'Invalid JSON' ) ;
end ;
2020-06-24 00:00:47 +02:00
Result : = lJSON;
except
on E: Exception do
begin
lJSON. Free;
2023-06-21 12:56:21 +02:00
Result : = nil ;
if ARaiseExceptionOnError then
begin
raise EMVCDeserializationException. Create( 'Invalid JSON Array - ' + E. Message ) ;
end ;
2018-12-12 14:48:35 +01:00
end ;
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure JsonObjectToObject( const AJSONObject: TJDOJsonObject; const AObject: TObject) ;
2020-09-22 15:18:22 +02:00
begin
2022-08-01 19:11:42 +02:00
JsonObjectToObject( AJSONObject, AObject, TMVCSerializationType. stDefault, nil )
2020-09-22 15:18:22 +02:00
end ;
procedure JsonArrayToList( const AJsonArray: TJDOJsonArray; const AList: IMVCList; const AClazz: TClass;
const AType: TMVCSerializationType; const AIgnoredAttributes: TMVCIgnoredList) ;
var
lSer: TMVCJsonDataObjectsSerializer;
I: Integer ;
lObj: TObject;
begin
lSer : = TMVCJsonDataObjectsSerializer. Create;
try
for I : = 0 to AJsonArray. Count - 1 do
begin
lObj : = AClazz. Create;
try
lSer. JsonObjectToObject( AJsonArray[ I] . ObjectValue, lObj, TMVCSerializationType. stDefault, nil ) ;
except
lObj. Free;
raise ;
end ;
end ;
finally
lSer. Free;
end ;
end ;
2022-08-01 19:11:42 +02:00
procedure JsonObjectToObject( const AJSONObject: TJDOJsonObject; const AObject: TObject;
2019-01-08 12:48:27 +01:00
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
2022-08-01 19:11:42 +02:00
lSer. JsonObjectToObject( AJSONObject, AObject, AType, AIgnoredAttributes) ;
2018-12-17 00:39:29 +01:00
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 }
2021-01-27 20:25:35 +01:00
procedure TJSONObjectHelper. LoadFromString( const Value: string ; Encoding: TEncoding; Utf8WithoutBOM: Boolean ) ;
2019-11-06 15:08:29 +01:00
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 ;
2022-07-05 16:18:03 +02:00
{ TMVCRecordHelper }
2022-08-01 19:11:42 +02:00
function TMVCJsonDataObjectsSerializer. JSONObjectToRecord< T> ( const JSONObject: TJsonObject) : T;
2022-07-05 16:18:03 +02:00
var
2022-07-10 23:30:00 +02:00
AIgnoredAttributes: TMVCIgnoredList;
lKeyName: string ;
lAttributeValue: TValue;
lErrMsg: string ;
2022-08-01 19:11:42 +02:00
lField: TRttiField;
2022-07-10 23:30:00 +02:00
lBuffer: PByte ;
2022-07-05 16:18:03 +02:00
lCtx: TRttiContext;
2022-07-10 23:30:00 +02:00
lRTTIType: TRttiType;
2022-07-05 16:18:03 +02:00
begin
2022-07-10 23:30:00 +02:00
lCtx : = GetRttiContext;
lRTTIType : = lCtx. GetType( TypeInfo( T) ) ;
if not lRTTIType. IsRecord then
begin
raise EMVCDeserializationException. Create( 'Extected record, got ' + lRTTIType. QualifiedName) ;
end ;
2022-07-05 16:18:03 +02:00
2022-07-10 23:30:00 +02:00
lBuffer : = @ Result ;
lField : = nil ;
AIgnoredAttributes : = [ ] ;
try
for lField in lRTTIType. GetFields do
if ( not TMVCSerializerHelper. HasAttribute< MVCDoNotDeserializeAttribute> ( lField) ) and
( not IsIgnoredAttribute( AIgnoredAttributes, lField. Name ) ) then
begin
lKeyName : = TMVCSerializerHelper. GetKeyName( lField, lRTTIType) ;
2023-03-13 15:43:46 +01:00
//issue 648
if lField. FieldType. IsRecord and not lField. FieldType. Handle. NameFld. ToString. StartsWith( 'Nullable' ) then
2022-07-10 23:30:00 +02:00
begin
JSONObjectToNestedRecordField( JSONObject. O[ lKeyName] , lField, 0 , lBuffer) ;
end
else
begin
lAttributeValue : = lField. GetValue( lBuffer) ;
2022-08-01 19:11:42 +02:00
JSONObjectPropertyToTValueForRecord( JSONObject, lKeyName, TMVCSerializationType. stFields, AIgnoredAttributes,
lAttributeValue, lField. GetAttributes, lField) ;
2022-07-10 23:30:00 +02:00
lField. SetValue( lBuffer, lAttributeValue) ;
end ;
end ;
except
on E: EInvalidCast do
2022-07-05 16:18:03 +02:00
begin
2022-07-10 23:30:00 +02:00
if lField < > nil then
begin
lErrMsg : = Format( 'Invalid class typecast for field "%s" [Expected: %s, Actual: %s]' ,
[ lKeyName, lField. FieldType. ToString( ) , JDO_TYPE_DESC[ JSONObject[ lKeyName] . Typ] ] ) ;
end
else
begin
lErrMsg : = Format( 'Invalid class typecast for field "%s" [Actual: %s]' ,
[ lKeyName, JDO_TYPE_DESC[ JSONObject[ lKeyName] . Typ] ] ) ;
end ;
raise EMVCException. Create( HTTP_STATUS. BadRequest, lErrMsg) ;
2022-07-05 16:18:03 +02:00
end ;
end ;
end ;
function TMVCJsonDataObjectsSerializer. StrToRecord< T> ( const AJSONString: String ) : T;
var
lSer: TMVCJsonDataObjectsSerializer;
2022-08-01 19:11:42 +02:00
LJObj: TJsonObject;
2022-07-05 16:18:03 +02:00
lBuff: PByte ;
begin
lSer : = TMVCJsonDataObjectsSerializer. Create( nil ) ;
try
2022-08-01 19:11:42 +02:00
LJObj : = StrToJSONObject( AJSONString) ;
2022-07-05 16:18:03 +02:00
try
lBuff : = @ Result ;
2022-08-01 19:11:42 +02:00
lSer. JSONObjectToNestedRecordField( LJObj, nil , 0 , lBuff) ;
2022-07-05 16:18:03 +02:00
finally
2022-08-01 19:11:42 +02:00
LJObj. Free;
2022-07-05 16:18:03 +02:00
end ;
finally
lSer. Free;
end ;
end ;
2022-07-25 15:32:31 +02:00
{ TJSONUtils }
2022-07-05 16:18:03 +02:00
2022-08-01 19:11:42 +02:00
class function TJSONUtils. JSONArrayToArrayOfRecord< T> ( const JSONArray: TJsonArray) : TArray< T> ;
2022-07-05 16:51:31 +02:00
var
I: Integer ;
lSer: TMVCJsonDataObjectsSerializer;
begin
lSer : = TMVCJsonDataObjectsSerializer. Create( nil ) ;
try
SetLength( Result , JSONArray. Count) ;
for I : = Low( Result ) to High( Result ) do
begin
Result [ I] : = JSONObjectToRecord< T> ( JSONArray. Items[ I] . ObjectValue, lSer) ;
end ;
finally
lSer. Free;
end ;
end ;
2022-08-01 19:11:42 +02:00
class function TJSONUtils. JSONArrayToListOf< T> ( const JSONArray: TJsonArray) : TObjectList< T> ;
var
I: Integer ;
lSer: TMVCJsonDataObjectsSerializer;
begin
lSer : = TMVCJsonDataObjectsSerializer. Create( nil ) ;
try
Result : = TObjectList< T> . Create( True ) ;
try
for I : = 0 to JSONArray. Count - 1 do
begin
Result . Add( JsonObjectToObject< T> ( JSONArray. Items[ I] . ObjectValue) ) ;
end ;
except
Result . Free;
raise ;
end ;
finally
lSer. Free;
end ;
end ;
class function TJSONUtils. JsonObjectToObject< T> ( const JSONObject: TJsonObject) : T;
var
lSer: TMVCJsonDataObjectsSerializer;
begin
lSer : = TMVCJsonDataObjectsSerializer. Create( nil ) ;
try
Result : = T. Create;
try
lSer. JsonObjectToObject( JSONObject, Result , TMVCSerializationType. stDefault, nil ) ;
except
Result . Free;
raise ;
end ;
finally
lSer. Free;
end ;
end ;
class function TJSONUtils. JSONObjectToRecord< T> ( const JSONObject: TJsonObject) : T;
2022-07-05 16:18:03 +02:00
var
lSer: TMVCJsonDataObjectsSerializer;
begin
lSer : = TMVCJsonDataObjectsSerializer. Create( nil ) ;
try
2022-07-05 16:51:31 +02:00
Result : = JSONObjectToRecord< T> ( JSONObject, lSer) ;
2022-07-05 16:18:03 +02:00
finally
lSer. Free;
end ;
end ;
2022-08-01 19:11:42 +02:00
class function TJSONUtils. JSONObjectToRecord< T> ( const JSONObject: TJsonObject;
2022-07-18 19:04:15 +02:00
const Serializer: TMVCJsonDataObjectsSerializer) : T;
2022-07-05 16:51:31 +02:00
begin
2022-07-18 19:04:15 +02:00
Result : = Serializer. JSONObjectToRecord< T> ( JSONObject) ;
2022-07-05 16:51:31 +02:00
end ;
2022-08-12 10:50:46 +02:00
{ TMVCJsonDataObjectsSerializer.TSerializationMetaInfo }
class function TMVCJsonDataObjectsSerializer. TSerializationMetaInfo. CreateFieldsMetaInfo(
const ADataSet: TDataSet; const ANameCase: TMVCNameCase;
const AIgnoredFields: TMVCIgnoredList) : TSerializationMetaInfo;
var
lField: TField;
I: Integer ;
lName: String ;
begin
Result . IgnoredFields : = AIgnoredFields;
Result . NameCase : = ANameCase;
SetLength( Result . FieldsMetaInfo, ADataSet. Fields. Count) ;
for I : = 0 to ADataSet. FieldCount - 1 do
begin
lField : = ADataSet. Fields[ I] ;
lName : = GetNameAs( ADataSet. Owner, lField. Name , lField. FieldName) ;
Result . FieldsMetaInfo[ I] . Ignored : = IsIgnoredAttribute( AIgnoredFields, lName)
or ( IsIgnoredComponent( ADataSet. Owner, lField. Name ) ) ;
Result . FieldsMetaInfo[ I] . NameAs : =
TMVCSerializerHelper. ApplyNameCase(
GetNameCase( ADataSet, ANameCase) , lName) ;
end ;
end ;
2017-03-01 21:40:57 +01:00
end .