Quick.Json.Serializer.pas 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044
  1. { ***************************************************************************
  2. Copyright (c) 2015-2021 Kike Pérez
  3. Unit : Quick.JSON.Serializer
  4. Description : Json Serializer
  5. Author : Kike Pérez
  6. Version : 1.12
  7. Created : 21/05/2018
  8. Modified : 07/02/2021
  9. This file is part of QuickLib: https://github.com/exilon/QuickLib
  10. ***************************************************************************
  11. Licensed under the Apache License, Version 2.0 (the "License");
  12. you may not use this file except in compliance with the License.
  13. You may obtain a copy of the License at
  14. http://www.apache.org/licenses/LICENSE-2.0
  15. Unless required by applicable law or agreed to in writing, software
  16. distributed under the License is distributed on an "AS IS" BASIS,
  17. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  18. See the License for the specific language governing permissions and
  19. limitations under the License.
  20. *************************************************************************** }
  21. unit Quick.Json.Serializer;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. {$IFDEF DEBUG_SERIALIZER}
  26. Quick.Debug.Utils,
  27. {$ENDIF}
  28. Classes,
  29. SysUtils,
  30. Rtti,
  31. TypInfo,
  32. Quick.Serializer.Intf,
  33. Quick.Base64,
  34. {$IFDEF FPC}
  35. rttiutils,
  36. fpjson,
  37. jsonparser,
  38. strUtils,
  39. //jsonreader,
  40. //fpjsonrtti,
  41. Quick.Json.fpc.Compatibility,
  42. {$ELSE}
  43. {$IFDEF DELPHIXE7_UP}
  44. System.Json,
  45. {$ELSE}
  46. Data.DBXJSON,
  47. {$ENDIF}
  48. {$IFDEF DELPHIRX10_UP}
  49. {$ENDIF}
  50. Variants,
  51. {$ENDIF}
  52. Generics.Collections,
  53. Quick.RTTI.Utils,
  54. DateUtils,
  55. Quick.Commons,
  56. Quick.JSON.Utils;
  57. type
  58. IJsonSerializer = ISerializer;
  59. EJsonSerializeError = class(Exception);
  60. EJsonDeserializeError = class(Exception);
  61. {$IFNDEF FPC}
  62. TNotSerializableProperty = class(TCustomAttribute);
  63. TCommentProperty = class(TCustomAttribute)
  64. private
  65. fComment : string;
  66. public
  67. constructor Create(const aComment: string);
  68. property Comment : string read fComment;
  69. end;
  70. TCustomNameProperty = class(TCustomAttribute)
  71. private
  72. fName : string;
  73. public
  74. constructor Create(const aName: string);
  75. property Name : string read fName;
  76. end;
  77. {$IFNDEF DELPHIXE7_UP}
  78. TJSONArrayHelper = class helper for Data.DBXJson.TJSONArray
  79. private
  80. function GetItem(aValue : Integer) : TJSONValue;
  81. public
  82. function Count : Integer;
  83. property Items[index : Integer] : TJSONValue read GetItem;
  84. procedure SetElements(aElements : TList<TJSONValue>);
  85. end;
  86. TJSONValueHelper = class helper for Data.DBXJson.TJSONValue
  87. public
  88. function ToJson : string;
  89. end;
  90. TJSONObjectHelper = class helper for Data.DBXJson.TJSONObject
  91. private
  92. function GetPair(aValue : Integer) : TJSONPair;
  93. public
  94. function Count : Integer;
  95. function GetValue(const aName : string) : TJSONValue;
  96. property Pairs[index : Integer] : TJSONPair read GetPair;
  97. end;
  98. {$ENDIF}
  99. {$ENDIF}
  100. TSerializeLevel = (slPublicProperty, slPublishedProperty);
  101. TRTTIJson = class
  102. type
  103. TGenericListType = (gtNone, gtList, gtObjectList);
  104. private
  105. fSerializeLevel : TSerializeLevel;
  106. fUseEnumNames : Boolean;
  107. fUseJsonCaseSense : Boolean;
  108. fUseBase64Stream : Boolean;
  109. function GetValue(aAddr: Pointer; aType: TRTTIType): TValue; overload;
  110. function GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue; overload;
  111. function IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
  112. function GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
  113. function GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
  114. {$IFNDEF FPC}
  115. function GetFieldValueFromRecord(const aValue : TValue; const FieldName : string) : TValue;
  116. {$ENDIF}
  117. procedure SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue); overload;
  118. procedure SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue); overload;
  119. {$IFDEF FPC}
  120. function FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
  121. function GetPropType(aPropInfo: PPropInfo): PTypeInfo;
  122. procedure LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
  123. {$ENDIF}
  124. {$IFNDEF FPC}
  125. function CreateInstance(aClass: TClass): TValue; overload;
  126. function CreateInstance(aType: TRttiType): TValue; overload;
  127. {$ENDIF}
  128. public
  129. constructor Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
  130. property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
  131. property UseJsonCaseSense : Boolean read fUseJsonCaseSense write fUseJsonCaseSense;
  132. property UseBase64Stream : Boolean read fUseBase64Stream write fUseBase64Stream;
  133. function GetJsonPairValueByName(aJson : TJSONObject; const aName : string) : TJsonValue;
  134. function GetJsonPairByName(aJson : TJSONObject; const aName : string) : TJSONPair;
  135. function IsGenericList(aObject : TObject) : Boolean;
  136. function IsStream(aObject : TObject) : Boolean;
  137. function IsGenericXArray(const aClassName : string) : Boolean;
  138. function GetGenericListType(aObject : TObject) : TGenericListType;
  139. //serialize methods
  140. function SerializeValue(const aValue : TValue) : TJSONValue;
  141. function SerializeObject(aObject : TObject) : TJSONObject; overload;
  142. function SerializeStream(aObject : TObject) : TJSONValue;
  143. {$IFNDEF FPC}
  144. function SerializeDynArray(const aValue: TValue; aMaxElements : Integer = -1) : TJsonArray;
  145. function SerializeRecord(const aValue : TValue) : TJSONValue;
  146. {$ELSE}
  147. function SerializeObject(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
  148. {$ENDIF}
  149. //deserialize methods
  150. function DeserializeClass(aType : TClass; const aJson : TJSONObject) : TObject;
  151. function DeserializeObject(aObject : TObject; const aJson : TJSONObject) : TObject; overload;
  152. function DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject; overload;
  153. function DeserializeStream(aObject : TObject; const aJson : TJSONValue) : TObject;
  154. {$IFNDEF FPC}
  155. function DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
  156. function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aJsonArray: TJSONArray) : TValue;
  157. function DeserializeRecord(const aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
  158. function DeserializeList(aObject: TObject; const aName : string; const aJson: TJSONObject) : TObject;
  159. procedure DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aJson : TJsonObject);
  160. {$ELSE}
  161. function DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
  162. procedure DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aJsonArray: TJSONArray);
  163. {$ENDIF}
  164. end;
  165. TJsonSerializer = class(TInterfacedObject,IJsonSerializer)
  166. strict private
  167. fSerializeLevel : TSerializeLevel;
  168. fUseEnumNames : Boolean;
  169. fUseJsonCaseSense : Boolean;
  170. fUseBase64Stream : Boolean;
  171. fRTTIJson : TRTTIJson;
  172. private
  173. procedure SetUseEnumNames(const Value: Boolean);
  174. procedure SetUseJsonCaseSense(const Value: Boolean);
  175. procedure SetSerializeLevel(const Value: TSerializeLevel);
  176. procedure SetUseBase64Stream(const Value: Boolean);
  177. public
  178. constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
  179. destructor Destroy; override;
  180. property SerializeLevel : TSerializeLevel read fSerializeLevel write SetSerializeLevel;
  181. property UseEnumNames : Boolean read fUseEnumNames write SetUseEnumNames;
  182. property UseJsonCaseSense : Boolean read fUseJsonCaseSense write SetUseJsonCaseSense;
  183. property UseBase64Stream : Boolean read fUseBase64Stream write SetUseBase64Stream;
  184. function JsonToObject(aType : TClass; const aJson: string) : TObject; overload;
  185. function JsonToObject(aObject : TObject; const aJson: string) : TObject; overload;
  186. function JsonStreamToObject(aObject : TObject; aJsonStream : TStream) : TObject;
  187. function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
  188. function ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
  189. procedure ObjectToJsonStream(aObject : TObject; aStream : TStream);
  190. function ValueToJson(const aValue : TValue; aIndent : Boolean = False) : string;
  191. function ValueToJsonString(const aValue : TValue; aIndent : Boolean = False) : string;
  192. function ArrayToJson<T>(aArray : TArray<T>; aIndent : Boolean = False) : string;
  193. function ArrayToJsonString<T>(aArray : TArray<T>; aIndent : Boolean = False) : string;
  194. {$IFNDEF FPC}
  195. function JsonToArray<T>(const aJson : string) : TArray<T>;
  196. function JsonToValue(const aJson: string): TValue;
  197. {$ENDIF}
  198. end;
  199. EJsonSerializerError = class(Exception);
  200. PPByte = ^PByte;
  201. resourcestring
  202. cNotSupportedDataType = 'Not supported data type "%s"';
  203. cSerializeObjectError = 'Serialize object "%s" error: %s';
  204. cSerializePropertyError = 'Property "%s" ("%s")';
  205. cNotSerializable = 'Object is not serializable';
  206. cNotValidJson = 'Not a valid Json';
  207. implementation
  208. { TRTTIJson }
  209. {$IFNDEF FPC}
  210. function TRTTIJson.DeserializeDynArray(aTypeInfo: PTypeInfo; aObject: TObject; const aJsonArray: TJSONArray) : TValue;
  211. var
  212. rType: PTypeInfo;
  213. len: NativeInt;
  214. pArr: Pointer;
  215. rItemValue: TValue;
  216. i: Integer;
  217. objClass: TClass;
  218. ctx : TRttiContext;
  219. json : TJSONObject;
  220. rDynArray : TRttiDynamicArrayType;
  221. propObj : TObject;
  222. begin
  223. if GetTypeData(aTypeInfo).DynArrElType = nil then Exit;
  224. if not assigned(aJsonArray) then Exit;
  225. len := aJsonArray.Count;
  226. rType := GetTypeData(aTypeInfo).DynArrElType^;
  227. pArr := nil;
  228. DynArraySetLength(pArr,aTypeInfo, 1, @len);
  229. try
  230. TValue.Make(@pArr,aTypeInfo, Result);
  231. rDynArray := ctx.GetType(Result.TypeInfo) as TRTTIDynamicArrayType;
  232. for i := 0 to aJsonArray.Count - 1 do
  233. begin
  234. rItemValue := nil;
  235. case rType.Kind of
  236. tkClass :
  237. begin
  238. if aJsonArray.Items[i] is TJSONObject then
  239. begin
  240. propObj := GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).AsObject;
  241. if propObj = nil then
  242. begin
  243. objClass := rType.TypeData.ClassType;
  244. rItemValue := DeserializeClass(objClass, TJSONObject(aJsonArray.Items[i]));
  245. end
  246. else
  247. begin
  248. DeserializeObject(propObj,TJSONObject(aJsonArray.Items[i]));
  249. end;
  250. end;
  251. end;
  252. tkRecord :
  253. begin
  254. json := TJSONObject(aJsonArray.Items[i]);
  255. rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
  256. rDynArray.ElementType),aObject,json);
  257. end;
  258. tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
  259. begin
  260. //skip these properties
  261. end
  262. else
  263. begin
  264. rItemValue := DeserializeType(aObject,rType.Kind,aTypeInfo,aJsonArray.Items[i].Value);
  265. end;
  266. end;
  267. if not rItemValue.IsEmpty then Result.SetArrayElement(i,rItemValue);
  268. end;
  269. //aProperty.SetValue(aObject,rValue);
  270. finally
  271. DynArrayClear(pArr,aTypeInfo);
  272. end;
  273. end;
  274. {$ELSE}
  275. procedure TRTTIJson.DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aJsonArray: TJSONArray);
  276. var
  277. rType: PTypeInfo;
  278. len: NativeInt;
  279. pArr: Pointer;
  280. rItemValue: TValue;
  281. i: Integer;
  282. objClass: TClass;
  283. propObj : TObject;
  284. rValue : TValue;
  285. begin
  286. if GetTypeData(aTypeInfo).ElType2 = nil then Exit;
  287. len := aJsonArray.Count;
  288. rType := GetTypeData(aTypeInfo).ElType2;
  289. pArr := nil;
  290. DynArraySetLength(pArr,aTypeInfo, 1, @len);
  291. try
  292. TValue.Make(@pArr,aTypeInfo, rValue);
  293. for i := 0 to aJsonArray.Count - 1 do
  294. begin
  295. rItemValue := nil;
  296. case rType.Kind of
  297. tkClass :
  298. begin
  299. if aJsonArray.Items[i] is TJSONObject then
  300. begin
  301. propObj := GetValue(PPByte(rValue.GetReferenceToRawData)^ +GetTypeData(aTypeInfo).elSize * i, GetTypeData(aTypeInfo).ElType2).AsObject;
  302. if propObj = nil then
  303. begin
  304. objClass := GetTypeData(aTypeInfo).ClassType;
  305. rItemValue := DeserializeClass(objClass, TJSONObject(aJsonArray.Items[i]));
  306. end
  307. else
  308. begin
  309. DeserializeObject(propObj,TJSONObject(aJsonArray.Items[i]));
  310. end;
  311. end;
  312. end;
  313. tkRecord :
  314. begin
  315. {json := TJSONObject(aJsonArray.Items[i]);
  316. rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
  317. rDynArray.ElementType),aObject,json); }
  318. end;
  319. tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
  320. begin
  321. //skip these properties
  322. end
  323. else
  324. begin
  325. rItemValue := DeserializeType(aObject,GetTypeData(aTypeInfo).ElType2.Kind,aPropertyName,aJsonArray.Items[i].Value);
  326. end;
  327. end;
  328. if not rItemValue.IsEmpty then rValue.SetArrayElement(i,rItemValue);
  329. end;
  330. //aProperty.SetValue(aObject,rValue);
  331. SetDynArrayProp(aObject,GetPropInfo(aObject,aPropertyName),pArr);
  332. finally
  333. DynArrayClear(pArr,aTypeInfo);
  334. end;
  335. end;
  336. {$ENDIF}
  337. {$IFNDEF FPC}
  338. function TRTTIJson.DeserializeRecord(const aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
  339. var
  340. ctx : TRttiContext;
  341. rRec : TRttiRecordType;
  342. rField : TRttiField;
  343. rValue : TValue;
  344. member : TJsonValue;
  345. jArray : TJSONArray;
  346. json : TJSONObject;
  347. objClass : TClass;
  348. propobj : TObject;
  349. begin
  350. rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
  351. for rField in rRec.GetFields do
  352. begin
  353. rValue := nil;
  354. //member := TJSONPair(aJson.GetValue(rField.Name));
  355. member := GetJsonPairValueByName(aJson,rField.Name);
  356. if member <> nil then
  357. case rField.FieldType.TypeKind of
  358. tkDynArray :
  359. begin
  360. jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
  361. try
  362. rValue := DeserializeDynArray(rField.FieldType.Handle,aObject,jArray);
  363. finally
  364. jArray.Free;
  365. end;
  366. end;
  367. tkClass :
  368. begin
  369. //if (member.JsonValue is TJSONObject) then
  370. begin
  371. propobj := rField.GetValue(@aRecord).AsObject;
  372. json := TJSONObject.ParseJSONValue(member.ToJson) as TJSONObject;
  373. try
  374. if propobj = nil then
  375. begin
  376. objClass := rField.FieldType.Handle^.TypeData.ClassType;// aProperty.PropertyType.Handle^.TypeData.ClassType;
  377. rValue := DeserializeClass(objClass,json);
  378. end
  379. else
  380. begin
  381. DeserializeObject(propobj,json);
  382. end;
  383. finally
  384. json.Free;
  385. end;
  386. end
  387. end;
  388. tkRecord :
  389. begin
  390. json := TJSONObject.ParseJSONValue(member.ToJson) as TJSONObject;
  391. try
  392. rValue := DeserializeRecord(rField.GetValue(aRecord.GetReferenceToRawData),aObject,json);
  393. finally
  394. json.Free;
  395. end;
  396. end
  397. else
  398. begin
  399. //rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.ToJson);
  400. //avoid return unicode escaped chars if string
  401. if rField.FieldType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
  402. {$IFDEF DELPHIRX10_UP}
  403. rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,TJsonValue(member).value)
  404. {$ELSE}
  405. rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.Value)
  406. {$ENDIF}
  407. else rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.ToJSON);
  408. end;
  409. end;
  410. if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
  411. end;
  412. Result := aRecord;
  413. end;
  414. function TRTTIJson.DeserializeStream(aObject: TObject; const aJson: TJSONValue): TObject;
  415. var
  416. stream : TStringStream;
  417. begin
  418. if fUseBase64Stream then stream := TStringStream.Create(Base64Decode(aJson.Value),TEncoding.Ansi)
  419. else stream := TStringStream.Create(aJson.Value,TEncoding.Ansi);
  420. try
  421. TStream(aObject).CopyFrom(stream,stream.Size);
  422. finally
  423. stream.Free;
  424. end;
  425. end;
  426. {$ENDIF}
  427. constructor TRTTIJson.Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
  428. begin
  429. fSerializeLevel := aSerializeLevel;
  430. fUseEnumNames := aUseEnumNames;
  431. fUseJsonCaseSense := False;
  432. fUseBase64Stream := True;
  433. end;
  434. {$IFNDEF FPC}
  435. function TRTTIJson.CreateInstance(aClass: TClass): TValue;
  436. var
  437. ctx : TRttiContext;
  438. rtype : TRttiType;
  439. begin
  440. Result := nil;
  441. rtype := ctx.GetType(aClass);
  442. Result := CreateInstance(rtype);
  443. end;
  444. {$ENDIF}
  445. {$IFNDEF FPC}
  446. function TRTTIJson.CreateInstance(aType: TRttiType): TValue;
  447. var
  448. rmethod : TRttiMethod;
  449. begin
  450. Result := nil;
  451. if atype = nil then Exit;
  452. for rmethod in TRttiInstanceType(atype).GetMethods do
  453. begin
  454. if rmethod.IsConstructor then
  455. begin
  456. //create if don't have parameters
  457. if Length(rmethod.GetParameters) = 0 then
  458. begin
  459. Result := rmethod.Invoke(TRttiInstanceType(atype).MetaclassType,[]);
  460. Break;
  461. end;
  462. end;
  463. end;
  464. end;
  465. {$ENDIF}
  466. function TRTTIJson.DeserializeClass(aType: TClass; const aJson: TJSONObject): TObject;
  467. begin
  468. Result := nil;
  469. if (aJson = nil) or ((aJson as TJSONValue) is TJSONNull) or (aJson.Count = 0) then Exit;
  470. {$IFNDEF FPC}
  471. Result := CreateInstance(aType).AsObject;
  472. {$ELSE}
  473. Result := aType.Create;
  474. {$ENDIF}
  475. try
  476. Result := DeserializeObject(Result,aJson);
  477. except
  478. on E : Exception do
  479. begin
  480. Result.Free;
  481. raise EJsonDeserializeError.CreateFmt('Deserialize error class "%s" : %s',[aType.ClassName,e.Message]);
  482. end;
  483. end;
  484. end;
  485. function TRTTIJson.DeserializeObject(aObject: TObject; const aJson: TJSONObject): TObject;
  486. var
  487. ctx: TRttiContext;
  488. rType: TRttiType;
  489. rProp: TRttiProperty;
  490. {$IFNDEF FPC}
  491. attr: TCustomAttribute;
  492. propvalue : TValue;
  493. {$ENDIF}
  494. propertyname : string;
  495. begin
  496. Result := aObject;
  497. if (aJson = nil) or ((aJson as TJSONValue) is TJSONNull) or (aJson.Count = 0) or (Result = nil) then Exit;
  498. try
  499. //if generic list
  500. {$IFNDEF FPC}
  501. if IsGenericList(aObject) then
  502. begin
  503. DeserializeList(aObject,'List',aJson);
  504. Exit;
  505. end
  506. else
  507. {$ENDIF}
  508. if IsStream(aObject) then
  509. begin
  510. DeserializeStream(aObject,aJson);
  511. Exit;
  512. end;
  513. //if standard object
  514. rType := ctx.GetType(aObject.ClassInfo);
  515. for rProp in rType.GetProperties do
  516. begin
  517. {$IFNDEF FPC}
  518. if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
  519. or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
  520. {$ENDIF}
  521. begin
  522. if ((rProp.IsWritable) or (rProp.Name = 'List')) and (IsAllowedProperty(aObject,rProp.Name)) then
  523. begin
  524. propertyname := rProp.Name;
  525. {$IFNDEF FPC}
  526. for attr in rProp.GetAttributes do if attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
  527. propvalue := rProp.GetValue(aObject);
  528. if rProp.Name = 'List' then
  529. begin
  530. Result := DeserializeList(Result,propertyname,aJson);
  531. end
  532. else if propvalue.IsObject then
  533. begin
  534. if propvalue.AsObject = nil then
  535. begin
  536. propvalue := CreateInstance(rProp.PropertyType);
  537. rProp.SetValue(aObject,propvalue);
  538. end;
  539. if IsGenericList(propvalue.AsObject) then DeserializeList(propvalue.AsObject,'List',TJSONObject(aJson.GetValue(propertyname)))
  540. else Result := DeserializeProperty(Result,propertyname,rProp,aJson);
  541. end
  542. else if IsGenericXArray(propvalue{$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF}) then
  543. begin
  544. DeserializeXArray(Result,propvalue,rProp,propertyname,aJson);
  545. end
  546. else
  547. {$ENDIF}
  548. Result := DeserializeProperty(Result,propertyname,rProp,aJson);
  549. end;
  550. end;
  551. end;
  552. except
  553. on E : Exception do
  554. begin
  555. Result.Free;
  556. raise EJsonDeserializeError.CreateFmt('Deserialize error for object "%s" : %s',[aObject.ClassName,e.Message]);
  557. end;
  558. end;
  559. end;
  560. {$IFNDEF FPC}
  561. function TRTTIJson.DeserializeList(aObject: TObject; const aName : string; const aJson: TJSONObject) : TObject;
  562. var
  563. ctx : TRttiContext;
  564. rType : TRttiType;
  565. jarray : TJSONArray;
  566. member : TJsonValue;
  567. rvalue : TValue;
  568. i : Integer;
  569. n : Integer;
  570. rProp : TRttiProperty;
  571. {$IFNDEF DELPHIRX10_UP}
  572. rfield : TRttiField;
  573. {$ENDIF}
  574. genericType : TGenericListType;
  575. begin
  576. Result := aObject;
  577. rType := ctx.GetType(aObject.ClassInfo);
  578. rProp := rType.GetProperty('List');
  579. if (rProp = nil) or (aJson = nil) or (aJson.ClassType = TJSONNull) then Exit;
  580. member := nil;
  581. //check if exists List (denotes delphi json serialized) or not (normal json serialized)
  582. if aJson.ClassType = TJSONObject then member := GetJsonPairValueByName(aJson,aName);
  583. if member = nil then
  584. begin
  585. if aJson.ClassType <> TJSONArray then raise EJsonDeserializeError.CreateFmt('Not valid value for "%s" List',[aName]);
  586. jArray := TJSONObject.ParseJSONValue(aJson.ToJSON) as TJSONArray;
  587. end
  588. else
  589. begin
  590. if member.ClassType <> TJSONArray then raise EJsonDeserializeError.CreateFmt('Not valid value for "%s" List',[aName]);
  591. jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
  592. end;
  593. try
  594. rvalue := DeserializeDynArray(rProp.PropertyType.Handle,Result,jArray);
  595. //i := jarray.Count;
  596. finally
  597. jArray.Free;
  598. end;
  599. if not rValue.IsEmpty then
  600. begin
  601. {$IFDEF DELPHIRX10_UP}
  602. if (TObjectList<TObject>(aObject) <> nil) and (rvalue.IsArray) then
  603. begin
  604. genericType := GetGenericListType(aObject);
  605. if genericType = TGenericListType.gtObjectList then TObjectList<TObject>(aObject).Clear
  606. else TList<TObject>(aObject).Clear;
  607. n := rvalue.GetArrayLength - 1;
  608. for i := 0 to n do
  609. begin
  610. if genericType = TGenericListType.gtObjectList then TObjectList<TObject>(aObject).Add(rvalue.GetArrayElement(i).AsObject)
  611. else TList<TObject>(aObject).Add(rvalue.GetArrayElement(i).AsObject);
  612. end;
  613. end;
  614. {$ELSE}
  615. n := 0;
  616. for rfield in rType.GetFields do
  617. begin
  618. if rfield.Name = 'FOwnsObjects' then rfield.SetValue(aObject,True);
  619. //if rfield.Name = 'FCount' then rfield.SetValue(aObject,i);
  620. if rfield.Name = 'FItems' then
  621. begin
  622. //if TList(aObject) <> nil then TList(aObject).Clear;
  623. //rfield.GetValue(aObject).AsObject.Free;// aValue.GetReferenceToRawData)
  624. rfield.SetValue(aObject,rValue);// .SetDynArrayProp(aObject,'fItems',Result);
  625. Break;
  626. end;
  627. end;
  628. rProp := rType.GetProperty('Count');
  629. rProp.SetValue(aObject,n);
  630. {$ENDIF}
  631. end;
  632. end;
  633. {$ENDIF}
  634. {$IFNDEF FPC}
  635. procedure TRTTIJson.DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aJson : TJsonObject);
  636. var
  637. ctx : TRttiContext;
  638. rRec : TRttiRecordType;
  639. rfield : TRttiField;
  640. rValue : TValue;
  641. member : TJsonValue;
  642. jArray : TJSONArray;
  643. begin
  644. rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
  645. rfield := rRec.GetField('fArray');
  646. if rfield <> nil then
  647. begin
  648. rValue := nil;
  649. //member := TJSONPair(aJson.GetValue(rField.Name));
  650. member := GetJsonPairValueByName(aJson,aPropertyName);
  651. if (member <> nil) and (rField.FieldType.TypeKind = tkDynArray) then
  652. begin
  653. jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
  654. try
  655. rValue := DeserializeDynArray(rField.FieldType.Handle,nil,jArray);
  656. finally
  657. jArray.Free;
  658. end;
  659. end;
  660. end;
  661. if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
  662. aProperty.SetValue(Instance,aRecord);
  663. end;
  664. {$ENDIF}
  665. function TRTTIJson.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject;
  666. var
  667. rValue : TValue;
  668. {$IFNDEF FPC}
  669. member : TJsonValue;
  670. {$ELSE}
  671. member : TJsonObject;
  672. {$ENDIF}
  673. objClass: TClass;
  674. jArray : TJSONArray;
  675. json : TJSONObject;
  676. begin
  677. Result := aObject;
  678. rValue := nil;
  679. {$IFNDEF FPC}
  680. //member := TJSONPair(aJson.GetValue(aName));
  681. member := GetJsonPairValueByName(aJson,aName);
  682. {$ELSE}
  683. member := TJsonObject(aJson.Find(aName));
  684. {$ENDIF}
  685. if member <> nil then
  686. begin
  687. case aProperty.PropertyType.TypeKind of
  688. tkDynArray :
  689. begin
  690. {$IFNDEF FPC}
  691. if member is TJSONNull then Exit;
  692. jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
  693. {$ELSE}
  694. if member.ClassType = TJSONNull.ClassType then Exit;
  695. jArray := TJSONArray(TJSONObject.ParseJSONValue(member.ToJSON));
  696. {$ENDIF}
  697. try
  698. {$IFNDEF FPC}
  699. aProperty.SetValue(aObject,DeserializeDynArray(aProperty.PropertyType.Handle,Result,jArray));
  700. {$ELSE}
  701. DeserializeDynArray(aProperty.PropertyType.Handle,aName,Result,jArray);
  702. {$ENDIF}
  703. Exit;
  704. finally
  705. jArray.Free;
  706. end;
  707. end;
  708. tkClass :
  709. begin
  710. //if (member.JsonValue is TJSONObject) then
  711. begin
  712. json := TJsonObject(TJSONObject.ParseJSONValue(member.ToJson));
  713. try
  714. if aProperty.GetValue(aObject).AsObject = nil then
  715. begin
  716. {$IFNDEF FPC}
  717. objClass := aProperty.PropertyType.Handle^.TypeData.ClassType;
  718. rValue := DeserializeClass(objClass,json);
  719. {$ELSE}
  720. objClass := GetObjectPropClass(aObject,aName);
  721. //objClass := GetTypeData(aProperty.PropertyType.Handle)^.ClassType;
  722. rValue := DeserializeClass(objClass,json);
  723. SetObjectProp(aObject,aName,rValue.AsObject);
  724. Exit;
  725. {$ENDIF}
  726. end
  727. else
  728. begin
  729. rValue := DeserializeObject(aProperty.GetValue(aObject).AsObject,json);
  730. Exit;
  731. end;
  732. finally
  733. json.Free;
  734. end;
  735. end
  736. end;
  737. {$IFNDEF FPC}
  738. tkRecord :
  739. begin
  740. if aProperty.GetValue(aObject).TypeInfo = System.TypeInfo(TGUID) then
  741. begin
  742. rValue:=TValue.From<TGUID>(StringToGUID(member.ToJSON.DeQuotedString('"')));
  743. end
  744. else
  745. begin
  746. json := TJSONObject.ParseJSONValue(member.ToJson) as TJSONObject;
  747. try
  748. rValue := DeserializeRecord(aProperty.GetValue(aObject),aObject,json);
  749. finally
  750. json.Free;
  751. end;
  752. end;
  753. end;
  754. {$ENDIF}
  755. else
  756. begin
  757. {$IFNDEF FPC}
  758. //avoid return unicode escaped chars if string
  759. if aProperty.PropertyType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
  760. {$IFDEF DELPHIRX10_UP}
  761. rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,TJsonValue(member).value)
  762. {$ELSE}
  763. rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.Value)
  764. {$ENDIF}
  765. else rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.ToJSON);
  766. {$ELSE}
  767. rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aName,member.ToJSON);
  768. if not rValue.IsEmpty then SetPropertyValue(aObject,aName,rValue);
  769. {$ENDIF}
  770. end;
  771. end;
  772. {$IFNDEF FPC}
  773. if not rValue.IsEmpty then aProperty.SetValue(Result,rValue);
  774. {$ENDIF}
  775. end;
  776. end;
  777. {$IFNDEF FPC}
  778. function TRTTIJson.DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
  779. var
  780. i : Integer;
  781. value : string;
  782. fsettings : TFormatSettings;
  783. begin
  784. try
  785. value := AnsiDequotedStr(aValue,'"');
  786. case aType of
  787. tkString, tkLString, tkWString, tkUString :
  788. begin
  789. Result := value;
  790. end;
  791. tkChar, tkWChar :
  792. begin
  793. Result := value;
  794. end;
  795. tkInteger :
  796. begin
  797. Result := StrToInt(value);
  798. end;
  799. tkInt64 :
  800. begin
  801. Result := StrToInt64(value);
  802. end;
  803. tkFloat :
  804. begin
  805. if aTypeInfo = TypeInfo(TDateTime) then
  806. begin
  807. if CompareText(value,'null') <> 0 then Result := JsonDateToDateTime(value);
  808. end
  809. else if aTypeInfo = TypeInfo(TDate) then
  810. begin
  811. if CompareText(value,'null') <> 0 then Result := StrToDate(value);
  812. end
  813. else if aTypeInfo = TypeInfo(TTime) then
  814. begin
  815. Result := StrToTime(value);
  816. end
  817. else
  818. begin
  819. fsettings := TFormatSettings.Create;
  820. Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
  821. end;
  822. end;
  823. tkEnumeration :
  824. begin
  825. if aTypeInfo = System.TypeInfo(Boolean) then
  826. begin
  827. Result := StrToBool(value);
  828. end
  829. else
  830. begin
  831. //if fUseEnumNames then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
  832. // else TValue.Make(StrToInt(value),aTypeInfo, Result);
  833. if not TryStrToInt(value,i) then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
  834. else TValue.Make(StrToInt(value),aTypeInfo, Result);
  835. end;
  836. end;
  837. tkSet :
  838. begin
  839. i := StringToSet(aTypeInfo,value);
  840. TValue.Make(@i,aTypeInfo,Result);
  841. end;
  842. else
  843. begin
  844. //raise EclJsonSerializerError.Create('Not supported data type!');
  845. end;
  846. end;
  847. except
  848. on E : Exception do
  849. begin
  850. raise EJsonDeserializeError.CreateFmt('Deserialize error type "%s.%s" : %s',[aObject.ClassName,GetTypeName(aTypeInfo),e.Message]);
  851. end;
  852. end;
  853. end;
  854. {$ELSE}
  855. function TRTTIJson.DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
  856. var
  857. value : string;
  858. propinfo : PPropInfo;
  859. fsettings : TFormatSettings;
  860. begin
  861. try
  862. value := AnsiDequotedStr(aValue,'"');
  863. if value = '' then
  864. begin
  865. Result := nil;
  866. Exit;
  867. end;
  868. propinfo := GetPropInfo(aObject,aPropertyName);
  869. //case propinfo.PropType.Kind of
  870. case aType of
  871. tkString, tkLString, tkWString, tkUString, tkAString :
  872. begin
  873. Result := value;
  874. //SetStrProp(aObject,propinfo,value);
  875. end;
  876. tkChar, tkWChar :
  877. begin
  878. Result := value;
  879. end;
  880. tkInteger :
  881. begin
  882. Result := StrToInt(value);
  883. end;
  884. tkInt64 :
  885. begin
  886. Result := StrToInt64(value);
  887. end;
  888. tkFloat :
  889. begin
  890. if propinfo.PropType = TypeInfo(TDateTime) then
  891. begin
  892. if CompareText(value,'null') <> 0 then Result := JsonDateToDateTime(value);
  893. end
  894. else if propinfo.PropType = TypeInfo(TDate) then
  895. begin
  896. if CompareText(value,'null') <> 0 then Result := StrToDate(value);
  897. end
  898. else if propinfo.PropType = TypeInfo(TTime) then
  899. begin
  900. Result := StrToTime(value);
  901. end
  902. else
  903. begin
  904. fsettings := DefaultFormatSettings;
  905. Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
  906. end;
  907. end;
  908. tkEnumeration:
  909. begin
  910. Result := value;
  911. end;
  912. tkBool :
  913. begin
  914. Result := StrToBool(value);
  915. end;
  916. tkSet :
  917. begin
  918. Result := value;
  919. end;
  920. else
  921. begin
  922. //raise EclJsonSerializerError.Create('Not supported data type!');
  923. end;
  924. end;
  925. //if not Result.IsEmpty then SetPropertyValue(aObject,propinfo,Result);
  926. except
  927. on E : Exception do
  928. begin
  929. raise EJsonDeserializeError.CreateFmt('Deserialize error type "%s" : %s',[aObject.ClassName,e.Message]);
  930. end;
  931. end;
  932. end;
  933. {$ENDIF}
  934. function TRTTIJson.IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
  935. var
  936. propname : string;
  937. begin
  938. Result := True;
  939. propname := aPropertyName.ToLower;
  940. if IsGenericList(aObject) then
  941. begin
  942. if (propname = 'capacity') or (propname = 'count') or (propname = 'ownsobjects') then Result := False;
  943. end
  944. else if (propname = 'refcount') then Result := False;
  945. end;
  946. function TRTTIJson.IsGenericList(aObject : TObject) : Boolean;
  947. var
  948. cname : string;
  949. begin
  950. if aObject = nil then Exit(False);
  951. cname := aObject.ClassName;
  952. Result := (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList'));
  953. end;
  954. function TRTTIJson.IsStream(aObject : TObject) : Boolean;
  955. begin
  956. if aObject = nil then Exit(False);
  957. Result := aObject.InheritsFrom(TStream);
  958. end;
  959. function TRTTIJson.GetGenericListType(aObject : TObject) : TGenericListType;
  960. var
  961. cname : string;
  962. begin
  963. if aObject = nil then Exit(TGenericListType.gtNone);
  964. cname := aObject.ClassName;
  965. if cname.StartsWith('TObjectList') then Result := TGenericListType.gtObjectList
  966. else if cname.StartsWith('TList') then Result := TGenericListType.gtList
  967. else Result := TGenericListType.gtNone;
  968. end;
  969. function TRTTIJson.IsGenericXArray(const aClassName : string) : Boolean;
  970. begin
  971. Result := aClassName.StartsWith('TXArray');
  972. end;
  973. function TRTTIJson.GetJsonPairValueByName(aJson: TJSONObject; const aName: string): TJsonValue;
  974. var
  975. candidate : TJSONPair;
  976. i : Integer;
  977. begin
  978. if fUseJsonCaseSense then
  979. begin
  980. Result := aJson.GetValue(aName);
  981. Exit;
  982. end
  983. else
  984. begin
  985. for i := 0 to aJson.Count - 1 do
  986. begin
  987. candidate := aJson.Pairs[I];
  988. if candidate.JsonValue = nil then continue;
  989. if CompareText(candidate.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then Exit(candidate.JsonValue);
  990. end;
  991. end;
  992. Result := nil;
  993. end;
  994. function TRTTIJson.GetJsonPairByName(aJson: TJSONObject; const aName: string): TJSONPair;
  995. var
  996. i : Integer;
  997. begin
  998. if fUseJsonCaseSense then
  999. begin
  1000. Result := TJSONPair(aJson.GetValue(aName));
  1001. Exit;
  1002. end
  1003. else
  1004. begin
  1005. if aJson <> nil then
  1006. begin
  1007. for i := 0 to aJson.Count - 1 do
  1008. begin
  1009. Result := aJson.Pairs[I];
  1010. if Result.JsonValue = nil then continue;
  1011. if CompareText(Result.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then Exit;
  1012. end;
  1013. end;
  1014. end;
  1015. Result := nil;
  1016. end;
  1017. function TRTTIJson.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
  1018. var
  1019. pinfo : PPropInfo;
  1020. begin
  1021. Result := nil;
  1022. pinfo := GetPropInfo(Instance,PropertyName);
  1023. if pinfo = nil then raise EJsonSerializeError.CreateFmt('Property "%s" not found!',[PropertyName]);
  1024. case pinfo.PropType^.Kind of
  1025. tkInteger : Result := GetOrdProp(Instance,pinfo);
  1026. tkInt64 : Result := GetInt64Prop(Instance,PropertyName);
  1027. tkFloat : Result := GetFloatProp(Instance,PropertyName);
  1028. tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
  1029. {$IFDEF FPC}
  1030. tkWString : Result := GetWideStrProp(Instance,PropertyName);
  1031. tkSString,
  1032. tkAString,
  1033. {$ELSE}
  1034. tkWString,
  1035. {$ENDIF}
  1036. tkLString : Result := GetStrProp(Instance,pinfo);
  1037. {$IFDEF FPC}
  1038. tkEnumeration :
  1039. begin
  1040. if fUseEnumNames then Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName))
  1041. else Result := GetOrdProp(Instance,PropertyName);
  1042. end;
  1043. {$ELSE}
  1044. tkEnumeration :
  1045. begin
  1046. if fUseEnumNames then Result := GetEnumName(@pinfo.PropType,GetOrdProp(Instance,PropertyName))
  1047. else Result := GetOrdProp(Instance,PropertyName);
  1048. end;
  1049. {$ENDIF}
  1050. tkSet : Result := GetSetProp(Instance,pinfo,True);
  1051. {$IFNDEF FPC}
  1052. tkClass :
  1053. {$ELSE}
  1054. tkBool : Result := Boolean(GetOrdProp(Instance,pinfo));
  1055. tkObject :
  1056. {$ENDIF} Result := GetObjectProp(Instance,pinfo);
  1057. tkDynArray : Result := GetDynArrayProp(Instance,pinfo);
  1058. end;
  1059. end;
  1060. function TRTTIJson.GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
  1061. var
  1062. ctx : TRttiContext;
  1063. rprop : TRttiProperty;
  1064. begin
  1065. rprop := ctx.GetType(Instance.ClassInfo).GetProperty(PropertyName);
  1066. Result := rprop.GetValue(Instance);
  1067. end;
  1068. {$IFNDEF FPC}
  1069. function TRTTIJson.GetFieldValueFromRecord(const aValue : TValue; const FieldName : string) : TValue;
  1070. var
  1071. ctx : TRttiContext;
  1072. rec : TRttiRecordType;
  1073. rfield : TRttiField;
  1074. begin
  1075. rec := ctx.GetType(aValue.TypeInfo).AsRecord;
  1076. rfield := rec.GetField(FieldName);
  1077. if rfield <> nil then Result := rField.GetValue(aValue.GetReferenceToRawData)
  1078. else Result := nil;
  1079. end;
  1080. {$ENDIF}
  1081. procedure TRTTIJson.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
  1082. var
  1083. pinfo : PPropInfo;
  1084. begin
  1085. pinfo := GetPropInfo(Instance,PropertyName);
  1086. SetPropertyValue(Instance,pinfo,aValue);
  1087. end;
  1088. procedure TRTTIJson.SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue);
  1089. begin
  1090. case aPropInfo.PropType^.Kind of
  1091. tkInteger : SetOrdProp(Instance,aPropInfo,aValue.AsInteger);
  1092. tkInt64 : SetInt64Prop(Instance,aPropInfo,aValue.AsInt64);
  1093. tkFloat : SetFloatProp(Instance,aPropInfo,aValue.AsExtended);
  1094. tkChar : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
  1095. {$IFDEF FPC}
  1096. tkWString : SetWideStrProp(Instance,aPropInfo,aValue.AsString);
  1097. tkSString,
  1098. tkAString,
  1099. {$ELSE}
  1100. tkWString,
  1101. {$ENDIF}
  1102. tkLString : SetStrProp(Instance,aPropInfo,aValue.AsString);
  1103. {$IFDEF FPC}
  1104. tkBool : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
  1105. tkSet : LoadSetProperty(Instance,aPropInfo,aValue.AsString);
  1106. {$ENDIF}
  1107. tkEnumeration : SetEnumProp(Instance,aPropInfo,aValue.AsString);
  1108. {$IFNDEF FPC}
  1109. tkClass :
  1110. {$ELSE}
  1111. tkObject :
  1112. {$ENDIF} SetObjectProp(Instance,aPropInfo,aValue.AsObject);
  1113. end;
  1114. end;
  1115. {$IFDEF FPC}
  1116. procedure TRTTIJson.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
  1117. type
  1118. TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
  1119. const
  1120. Delims = [' ', ',', '[', ']'];
  1121. var
  1122. TypeInfo: PTypeInfo;
  1123. W: Cardinal;
  1124. I, N: Integer;
  1125. Count: Integer;
  1126. EnumName: string;
  1127. begin
  1128. W := 0;
  1129. TypeInfo := GetTypeData(GetPropType(aPropInfo))^.CompType;
  1130. Count := WordCount(aValue, Delims);
  1131. for N := 1 to Count do
  1132. begin
  1133. EnumName := ExtractWord(N, aValue, Delims);
  1134. try
  1135. I := GetEnumValue(TypeInfo, EnumName);
  1136. if I >= 0 then Include(TCardinalSet(W),I);
  1137. except
  1138. end;
  1139. end;
  1140. SetOrdProp(aInstance,aPropInfo,W);
  1141. end;
  1142. {$ENDIF}
  1143. function TRTTIJson.SerializeObject(aObject: TObject): TJSONObject;
  1144. var
  1145. ctx: TRttiContext;
  1146. {$IFNDEF FPC}
  1147. attr : TCustomAttribute;
  1148. comment : string;
  1149. {$ENDIF}
  1150. rType: TRttiType;
  1151. rProp: TRttiProperty;
  1152. jpair : TJSONPair;
  1153. ExcludeSerialize : Boolean;
  1154. propertyname : string;
  1155. propvalue : TValue;
  1156. begin
  1157. if (aObject = nil) then
  1158. begin
  1159. Result := nil;
  1160. Exit;
  1161. end;
  1162. Result := nil;
  1163. try
  1164. //if is GenericList
  1165. if IsGenericList(aObject) then
  1166. begin
  1167. //get list array
  1168. propvalue := GetPropertyValueFromObject(aObject,'List');
  1169. {$IFDEF DELPHIRX10_UP}
  1170. Result := TJSONObject(SerializeDynArray(propvalue,TList<TObject>(aObject).Count));
  1171. {$ELSE}
  1172. Result := TJSONObject(SerializeValue(propvalue));
  1173. {$ENDIF}
  1174. Exit;
  1175. end
  1176. {$IFNDEF FPC}
  1177. else if IsStream(aObject) then
  1178. begin
  1179. Result := TJSONObject(SerializeStream(aObject));
  1180. Exit;
  1181. end
  1182. {$ENDIF}
  1183. else Result := TJSONObject.Create;
  1184. //if is standard object
  1185. propertyname := '';
  1186. rType := ctx.GetType(aObject.ClassInfo);
  1187. for rProp in TRTTI.GetProperties(rType,roFirstBase) do
  1188. begin
  1189. ExcludeSerialize := False;
  1190. propertyname := rProp.Name;
  1191. {$IFNDEF FPC}
  1192. comment := '';
  1193. if not rProp.IsReadable then Continue;
  1194. for attr in rProp.GetAttributes do
  1195. begin
  1196. if attr is TNotSerializableProperty then ExcludeSerialize := True
  1197. else if attr is TCommentProperty then comment := TCommentProperty(attr).Comment
  1198. else if attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
  1199. end;
  1200. if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
  1201. or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
  1202. {$ENDIF}
  1203. begin
  1204. if (IsAllowedProperty(aObject,propertyname)) and (not ExcludeSerialize) then
  1205. begin
  1206. //add comment as pair
  1207. {$IFNDEF FPC}
  1208. if comment <> '' then Result.AddPair(TJSONPair.Create('#Comment#->'+propertyname,Comment));
  1209. {$ENDIF}
  1210. begin
  1211. propvalue := rProp.GetValue(aObject);
  1212. jpair := TJSONPair.Create(propertyName,nil);
  1213. // if (propvalue.IsObject) and (IsGenericList(propvalue.AsObject)) then
  1214. // begin
  1215. // jpair.JsonValue := SerializeValue(GetPropertyValueFromObject(propvalue.AsObject,'List'));
  1216. // end
  1217. if propvalue.IsObject then jpair.JsonValue := SerializeObject(propvalue.AsObject)
  1218. {$IFNDEF FPC}
  1219. else if (not propvalue.IsObject) and (IsGenericXArray(propvalue{$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
  1220. begin
  1221. jpair.JsonValue := SerializeValue(GetFieldValueFromRecord(propvalue,'fArray'));
  1222. end
  1223. {$ENDIF}
  1224. else
  1225. begin
  1226. {$IFNDEF FPC}
  1227. jpair.JsonValue := SerializeValue(propvalue);
  1228. {$ELSE}
  1229. jpair.JsonValue := SerializeValue(propvalue);// SerializeObject(aObject,rProp.PropertyType.TypeKind,propertyname);
  1230. {$ENDIF}
  1231. end;
  1232. //s := jpair.JsonValue.ToString;
  1233. if jpair.JsonValue <> nil then
  1234. begin
  1235. Result.AddPair(jpair);
  1236. end
  1237. else jpair.Free;
  1238. end;
  1239. end;
  1240. end;
  1241. end;
  1242. except
  1243. on E : Exception do
  1244. begin
  1245. if Result <> nil then Result.Free;
  1246. if not propertyname.IsEmpty then raise EJsonSerializeError.CreateFmt('Serialize Error -> Object property: "%s" (%s)',[propertyname,e.Message])
  1247. else raise EJsonSerializeError.CreateFmt('Serialize Error -> Object (%s)',[e.Message]);
  1248. end;
  1249. end;
  1250. end;
  1251. function TRTTIJson.GetValue(aAddr: Pointer; aType: TRTTIType): TValue;
  1252. begin
  1253. TValue.Make(aAddr,aType.Handle,Result);
  1254. end;
  1255. function TRTTIJson.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
  1256. begin
  1257. TValue.Make(aAddr,aTypeInfo,Result);
  1258. end;
  1259. function TRTTIJson.SerializeValue(const aValue : TValue) : TJSONValue;
  1260. begin
  1261. Result := nil;
  1262. case avalue.Kind of
  1263. tkDynArray :
  1264. begin
  1265. {$IFNDEF FPC}
  1266. Result := SerializeDynArray(aValue);
  1267. {$ENDIF}
  1268. end;
  1269. tkClass :
  1270. begin
  1271. Result := TJSONValue(SerializeObject(aValue.AsObject));
  1272. end;
  1273. tkString, tkLString, tkWString, tkUString :
  1274. begin
  1275. Result := TJSONString.Create(aValue.AsString);
  1276. end;
  1277. tkChar, tkWChar :
  1278. begin
  1279. Result := TJSONString.Create(aValue.AsString);
  1280. end;
  1281. tkInteger :
  1282. begin
  1283. Result := TJSONNumber.Create(aValue.AsInteger);
  1284. end;
  1285. tkInt64 :
  1286. begin
  1287. Result := TJSONNumber.Create(aValue.AsInt64);
  1288. end;
  1289. tkFloat :
  1290. begin
  1291. if aValue.TypeInfo = TypeInfo(TDateTime) then
  1292. begin
  1293. if aValue.AsExtended <> 0.0 then Result := TJSONString.Create(DateTimeToJsonDate(aValue.AsExtended));
  1294. end
  1295. else if aValue.TypeInfo = TypeInfo(TDate) then
  1296. begin
  1297. if aValue.AsExtended <> 0.0 then Result := TJSONString.Create(DateToStr(aValue.AsExtended));
  1298. end
  1299. else if aValue.TypeInfo = TypeInfo(TTime) then
  1300. begin
  1301. Result := TJSONString.Create(TimeToStr(aValue.AsExtended));
  1302. end
  1303. else
  1304. begin
  1305. Result := TJSONNumber.Create(aValue.AsExtended);
  1306. end;
  1307. end;
  1308. tkEnumeration :
  1309. begin
  1310. if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
  1311. begin
  1312. {$IF Defined(DELPHIRX10_UP) OR Defined(FPC)}
  1313. Result := TJSONBool.Create(aValue.AsBoolean);
  1314. {$ELSE}
  1315. if aValue.AsBoolean then Result := TJsonTrue.Create
  1316. else Result := TJsonFalse.Create;
  1317. {$ENDIF}
  1318. end
  1319. else
  1320. begin
  1321. //Result.JsonValue := TJSONString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
  1322. if fUseEnumNames then Result := TJSONString.Create(aValue.ToString)
  1323. else Result := TJSONNumber.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
  1324. end;
  1325. end;
  1326. {$IFDEF FPC}
  1327. tkBool :
  1328. begin
  1329. Result := TJSONBool.Create(aValue.AsBoolean);
  1330. end;
  1331. {$ENDIF}
  1332. tkSet :
  1333. begin
  1334. Result := TJSONString.Create(aValue.ToString);
  1335. end;
  1336. tkRecord :
  1337. begin
  1338. {$IFNDEF FPC}
  1339. Result := SerializeRecord(aValue);
  1340. {$ENDIF}
  1341. end;
  1342. tkVariant :
  1343. begin
  1344. {$IFNDEF FPC}
  1345. case VarType(aValue.AsVariant) and VarTypeMask of
  1346. varInteger, varInt64 : Result := TJSONNumber.Create(aValue.AsInteger);
  1347. varString, varUString, varEmpty : Result := TJSONString.Create(aValue.AsString);
  1348. varDouble : Result := TJSONNumber.Create(aValue.AsExtended);
  1349. end;
  1350. {$ENDIF}
  1351. end;
  1352. tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure, tkUnknown :
  1353. begin
  1354. //skip these properties
  1355. end
  1356. else
  1357. begin
  1358. {$IFNDEF FPC}
  1359. raise EJsonSerializeError.CreateFmt(cNotSupportedDataType,[GetTypeName(aValue.TypeInfo)]);
  1360. {$ELSE}
  1361. raise EJsonSerializeError.Create('Not supported Data Type');
  1362. {$ENDIF}
  1363. end;
  1364. end;
  1365. if Result = nil then Result := TJSONNull.Create;
  1366. end;
  1367. {$IFNDEF FPC}
  1368. function TRTTIJson.SerializeDynArray(const aValue: TValue; aMaxElements : Integer = -1) : TJsonArray;
  1369. var
  1370. ctx : TRttiContext;
  1371. rDynArray : TRTTIDynamicArrayType;
  1372. i : Integer;
  1373. jValue : TJSONValue;
  1374. element : Integer;
  1375. list : TList<TJSONValue>;
  1376. len : Integer;
  1377. begin
  1378. element := -1;
  1379. Result := TJSONArray.Create;
  1380. try
  1381. rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
  1382. //if aValue.IsObjectInstance then TList<TObject>(aValue.AsObject).TrimExcess;
  1383. list := TList<TJSONValue>.Create;
  1384. if aMaxElements = -1 then len := aValue.GetArrayLength
  1385. else len := aMaxElements;
  1386. list.Capacity := len;
  1387. for i := 0 to len - 1 do
  1388. begin
  1389. if not GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).IsEmpty then
  1390. begin
  1391. element := i;
  1392. jValue := SerializeValue(GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType));
  1393. if jValue = nil then jValue := TJSONNull.Create;
  1394. list.Add(jValue);
  1395. end;
  1396. end;
  1397. Result.SetElements(list);
  1398. except
  1399. on E : Exception do
  1400. begin
  1401. if element > -1 then raise EJsonSerializeError.CreateFmt('Serialize Error -> Array[%d] (%s)',[element,e.Message])
  1402. else raise EJsonSerializeError.CreateFmt('Serialize Error -> Array (%s)',[e.Message]);
  1403. end;
  1404. end;
  1405. end;
  1406. function TRTTIJson.SerializeRecord(const aValue : TValue) : TJSONValue;
  1407. var
  1408. ctx : TRttiContext;
  1409. json : TJSONObject;
  1410. rRec : TRttiRecordType;
  1411. rField : TRttiField;
  1412. begin
  1413. rField := nil;
  1414. try
  1415. rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
  1416. if aValue.TypeInfo = System.TypeInfo(TGUID) then
  1417. begin
  1418. Result := TJSONString.Create(GUIDToString(aValue.AsType<TGUID>));
  1419. end
  1420. else
  1421. begin
  1422. json := TJSONObject.Create;
  1423. for rField in rRec.GetFields do
  1424. begin
  1425. json.AddPair(rField.Name,SerializeValue(rField.GetValue(aValue.GetReferenceToRawData)));
  1426. end;
  1427. Result := json;
  1428. end;
  1429. except
  1430. on E : Exception do
  1431. begin
  1432. if rField <> nil then raise EJsonSerializeError.CreateFmt('Serialize Error -> Record property "%s" (%s)',[rField.Name,e.Message])
  1433. else raise EJsonSerializeError.CreateFmt('Serialize Error -> Record (%s)',[e.Message]);
  1434. end;
  1435. end;
  1436. end;
  1437. function TRTTIJson.SerializeStream(aObject: TObject): TJSONValue;
  1438. var
  1439. stream : TStream;
  1440. json : string;
  1441. begin
  1442. Result := nil;
  1443. try
  1444. stream := TStream(aObject);
  1445. if fUseBase64Stream then Result := TJSONString.Create(Base64Encode(StreamToString(stream,TEncoding.Ansi)))
  1446. else Result := TJSONString.Create(StreamToString(stream,TEncoding.Ansi));
  1447. except
  1448. on E : Exception do
  1449. begin
  1450. EJsonSerializeError.CreateFmt('Serialize Error -> Stream (%s)',[e.Message]);
  1451. end;
  1452. end;
  1453. end;
  1454. {$ELSE}
  1455. function TRTTIJson.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
  1456. begin
  1457. Result := aPropInfo^.PropType;
  1458. end;
  1459. function TRTTIJson.FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
  1460. const
  1461. Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
  1462. var
  1463. fsettings : TFormatSettings;
  1464. begin
  1465. fsettings := FormatSettings;
  1466. Result := StringReplace(FloatToStrF(GetFloatProp(aObject, aPropInfo), ffGeneral,
  1467. Precisions[GetTypeData(GetPropType(aPropInfo))^.FloatType],0),
  1468. '.',fsettings.DecimalSeparator,[rfReplaceAll]);
  1469. end;
  1470. function TRTTIJson.SerializeObject(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
  1471. var
  1472. propinfo : PPropInfo;
  1473. jArray : TJsonArray;
  1474. jPair : TJsonPair;
  1475. jValue : TJsonValue;
  1476. i : Integer;
  1477. pArr : Pointer;
  1478. rValue : TValue;
  1479. rItemValue : TValue;
  1480. len : Integer;
  1481. begin
  1482. try
  1483. Result := TJSONPair.Create(aPropertyName,nil);
  1484. propinfo := GetPropInfo(aObject,aPropertyName);
  1485. //case propinfo.PropType.Kind of
  1486. case aType of
  1487. tkDynArray :
  1488. begin
  1489. len := 0;
  1490. jArray := TJSONArray.Create;
  1491. try
  1492. pArr := GetDynArrayProp(aObject,aPropertyName);
  1493. TValue.Make(@pArr,propinfo.PropType, rValue);
  1494. if rValue.IsArray then
  1495. begin
  1496. len := rValue.GetArrayLength;
  1497. for i := 0 to len - 1 do
  1498. begin
  1499. rItemValue := rValue.GetArrayElement(i);
  1500. jValue := SerializeValue(rItemValue);
  1501. jArray.Add(jValue);
  1502. end;
  1503. end;
  1504. Result.JsonValue := jArray;
  1505. finally
  1506. //DynArrayClear(pArr,propinfo.PropType);
  1507. pArr := nil;
  1508. end;
  1509. end;
  1510. tkClass :
  1511. begin
  1512. Result.JsonValue := TJSONValue(SerializeObject(GetObjectProp(aObject,aPropertyName)));
  1513. end;
  1514. tkString, tkLString, tkWString, tkUString, tkAString :
  1515. begin
  1516. Result.JsonValue := TJSONString.Create(GetStrProp(aObject,aPropertyName));
  1517. end;
  1518. tkChar, tkWChar :
  1519. begin
  1520. Result.JsonValue := TJSONString.Create(Char(GetOrdProp(aObject,aPropertyName)));
  1521. end;
  1522. tkInteger :
  1523. begin
  1524. Result.JsonValue := TJSONNumber.Create(GetOrdProp(aObject,aPropertyName));
  1525. end;
  1526. tkInt64 :
  1527. begin
  1528. Result.JsonValue := TJSONNumber.Create(GetOrdProp(aObject,aPropertyName));
  1529. end;
  1530. tkFloat :
  1531. begin
  1532. if propinfo.PropType = TypeInfo(TDateTime) then
  1533. begin
  1534. Result.JsonValue := TJSONString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
  1535. end
  1536. else if propinfo.PropType = TypeInfo(TDate) then
  1537. begin
  1538. Result.JsonValue := TJSONString.Create(DateToStr(GetFloatProp(aObject,aPropertyName)));
  1539. end
  1540. else if propinfo.PropType = TypeInfo(TTime) then
  1541. begin
  1542. Result.JsonValue := TJSONString.Create(TimeToStr(GetFloatProp(aObject,aPropertyName)));
  1543. end
  1544. else
  1545. begin
  1546. //Result.JsonValue := TJsonFloatNumber.Create(GetFloatProp(aObject,aPropertyName));
  1547. Result.JsonValue := TJsonFloatNumber.Create(StrToFloat(FloatProperty(aObject,propinfo)));
  1548. end;
  1549. end;
  1550. tkEnumeration,tkBool :
  1551. begin
  1552. if (propinfo.PropType = System.TypeInfo(Boolean)) then
  1553. begin
  1554. Result.JsonValue := TJSONBool.Create(Boolean(GetOrdProp(aObject,aPropertyName)));
  1555. end
  1556. else
  1557. begin
  1558. if fUseEnumNames then Result.JsonValue := TJSONString.Create(GetEnumName(propinfo.PropType,GetOrdProp(aObject,aPropertyName)))
  1559. else Result.JsonValue := TJSONNumber.Create(GetOrdProp(aObject,aPropertyName));
  1560. //Result.JsonValue := TJSONString.Create(aValue.ToString);
  1561. end;
  1562. end;
  1563. tkSet :
  1564. begin
  1565. Result.JsonValue := TJSONString.Create(GetSetProp(aObject,aPropertyName));
  1566. end;
  1567. {$IFNDEF FPC}
  1568. tkRecord :
  1569. begin
  1570. Result.JsonValue := SerializeRecord(aValue);
  1571. end;
  1572. {$ENDIF}
  1573. tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
  1574. begin
  1575. //skip these properties
  1576. //FreeAndNil(Result);
  1577. end
  1578. else
  1579. begin
  1580. //raise EJsonDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
  1581. end;
  1582. end;
  1583. if Result.JsonValue = nil then Result.JsonValue := TJSONNull.Create;
  1584. except
  1585. on E : Exception do
  1586. begin
  1587. Result.Free;
  1588. {$IFNDEF FPC}
  1589. raise EJsonSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
  1590. {$ENDIF}
  1591. end;
  1592. end;
  1593. end;
  1594. {$ENDIF}
  1595. { TJsonSerializer}
  1596. constructor TJsonSerializer.Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
  1597. begin
  1598. {$IFDEF FPC}
  1599. if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EJsonSerializeError.Create('FreePascal RTTI only supports published properties');
  1600. {$ENDIF}
  1601. fSerializeLevel := aSerializeLevel;
  1602. fUseEnumNames := aUseEnumNames;
  1603. fUseJsonCaseSense := False;
  1604. fUseBase64Stream := True;
  1605. fRTTIJson := TRTTIJson.Create(aSerializeLevel,aUseEnumNames);
  1606. fRTTIJson.UseJsonCaseSense := fUseJsonCaseSense;
  1607. fRTTIJson.UseBase64Stream := fUseBase64Stream;
  1608. end;
  1609. destructor TJsonSerializer.Destroy;
  1610. begin
  1611. fRTTIJson.Free;
  1612. inherited;
  1613. end;
  1614. function TJsonSerializer.JsonToObject(aType: TClass; const aJson: string): TObject;
  1615. var
  1616. json: TJSONObject;
  1617. begin
  1618. {$IFDEF DEBUG_SERIALIZER}
  1619. TDebugger.TimeIt(Self,'JsonToObject',aType.ClassName);
  1620. {$ENDIF}
  1621. try
  1622. {$IFDEF DELPHIRX10_UP}
  1623. json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
  1624. {$ELSE}
  1625. {$IFDEF FPC}
  1626. json := TJSONObject(TJSONObject.ParseJSONValue(aJson,True));
  1627. {$ELSE}
  1628. json := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONObject;
  1629. {$ENDIF}
  1630. {$ENDIF}
  1631. except
  1632. raise EJsonDeserializeError.Create(cNotValidJson);
  1633. end;
  1634. try
  1635. Result := fRTTIJson.DeserializeClass(aType,json);
  1636. finally
  1637. json.Free;
  1638. end;
  1639. end;
  1640. function TJsonSerializer.JsonToObject(aObject: TObject; const aJson: string): TObject;
  1641. var
  1642. jvalue : TJSONValue;
  1643. json: TJSONObject;
  1644. begin;
  1645. if aObject = nil then raise EJsonDeserializeError.Create('Object param cannot be null!');
  1646. {$IFDEF DEBUG_SERIALIZER}
  1647. TDebugger.TimeIt(Self,'JsonToObject',aObject.ClassName);
  1648. {$ENDIF}
  1649. try
  1650. {$IFDEF DELPHIRX10_UP}
  1651. jvalue := TJSONObject.ParseJSONValue(aJson,True);
  1652. if jvalue.ClassType = TJSONArray then json := TJSONObject(jvalue)
  1653. else json := jvalue as TJSONObject;
  1654. //json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
  1655. {$ELSE}
  1656. {$IFDEF FPC}
  1657. json := TJSONObject(TJSONObject.ParseJSONValue(aJson,True));
  1658. {$ELSE}
  1659. json := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONObject;
  1660. {$ENDIF}
  1661. {$ENDIF}
  1662. except
  1663. raise EJsonDeserializeError.Create(cNotValidJson);
  1664. end;
  1665. try
  1666. Result := fRTTIJson.DeserializeObject(aObject,json);
  1667. finally
  1668. json.Free;
  1669. end;
  1670. end;
  1671. function TJsonSerializer.ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
  1672. var
  1673. json: TJSONObject;
  1674. begin
  1675. {$IFDEF DEBUG_SERIALIZER}
  1676. TDebugger.TimeIt(Self,'ObjectToJson',aObject.ClassName);
  1677. {$ENDIF}
  1678. json := fRTTIJson.SerializeObject(aObject);
  1679. try
  1680. if aIndent then Result := TJsonUtils.JsonFormat(json.ToJSON)
  1681. else Result := json.ToJSON;
  1682. finally
  1683. json.Free;
  1684. end;
  1685. end;
  1686. procedure TJsonSerializer.ObjectToJsonStream(aObject: TObject; aStream: TStream);
  1687. var
  1688. json : TJsonObject;
  1689. ss : TStringStream;
  1690. begin
  1691. {$IFDEF DEBUG_SERIALIZER}
  1692. TDebugger.TimeIt(Self,'ObjectToJsonStream',aObject.ClassName);
  1693. {$ENDIF}
  1694. if aStream = nil then raise EJsonSerializeError.Create('stream parameter cannot be nil!');
  1695. json := fRTTIJson.SerializeObject(aObject);
  1696. try
  1697. ss := TStringStream.Create(json.ToString,TEncoding.UTF8);
  1698. try
  1699. aStream.CopyFrom(ss,ss.Size);
  1700. finally
  1701. ss.Free;
  1702. end;
  1703. finally
  1704. json.Free;
  1705. end;
  1706. end;
  1707. function TJsonSerializer.ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
  1708. var
  1709. json: TJSONObject;
  1710. begin
  1711. {$IFDEF DEBUG_SERIALIZER}
  1712. TDebugger.TimeIt(Self,'ObjectToJsonString',aObject.ClassName);
  1713. {$ENDIF}
  1714. json := fRTTIJson.SerializeObject(aObject);
  1715. try
  1716. if aIndent then Result := TJsonUtils.JsonFormat(json.ToString)
  1717. else Result := json.ToString;
  1718. finally
  1719. json.Free;
  1720. end;
  1721. end;
  1722. function TJsonSerializer.ValueToJson(const aValue: TValue; aIndent: Boolean): string;
  1723. var
  1724. json: TJSONValue;
  1725. begin
  1726. {$IFDEF DEBUG_SERIALIZER}
  1727. TDebugger.TimeIt(Self,'ValueToJson',aValue.ToString);
  1728. {$ENDIF}
  1729. json:= fRTTIJson.SerializeValue(aValue);
  1730. if json = nil then raise EJsonSerializerError.Create('Error serializing TValue');
  1731. try
  1732. if aIndent then Result := TJsonUtils.JsonFormat(json{$IFNDEF FPC}.ToJSON{$ELSE}.AsJson{$ENDIF})
  1733. else Result := json{$IFNDEF FPC}.ToJSON{$ELSE}.AsJson{$ENDIF};
  1734. finally
  1735. json.Free;
  1736. end;
  1737. end;
  1738. function TJsonSerializer.ValueToJsonString(const aValue: TValue; aIndent: Boolean): string;
  1739. var
  1740. json: TJSONValue;
  1741. begin
  1742. {$IFDEF DEBUG_SERIALIZER}
  1743. TDebugger.TimeIt(Self,'ValueToJsonString',aValue.ToString);
  1744. {$ENDIF}
  1745. json:= fRTTIJson.SerializeValue(aValue);
  1746. if json = nil then raise EJsonSerializerError.Create('Error serializing TValue');
  1747. try
  1748. if aIndent then Result := TJsonUtils.JsonFormat(json.ToString)
  1749. else Result := json.ToString;
  1750. finally
  1751. json.Free;
  1752. end;
  1753. end;
  1754. function TJsonSerializer.ArrayToJson<T>(aArray: TArray<T>; aIndent: Boolean): string;
  1755. var
  1756. json: TJSONValue;
  1757. begin
  1758. {$IFDEF DEBUG_SERIALIZER}
  1759. TDebugger.TimeIt(Self,'ArrayToJson','');
  1760. {$ENDIF}
  1761. json:= fRTTIJson.SerializeValue(TValue.From<TArray<T>>(aArray));
  1762. if json = nil then raise EJsonSerializerError.Create('Error serializing Array');
  1763. try
  1764. if aIndent then Result := TJsonUtils.JsonFormat(json{$IFNDEF FPC}.ToJSON{$ELSE}.AsJson{$ENDIF})
  1765. else Result := json{$IFNDEF FPC}.ToJSON{$ELSE}.AsJson{$ENDIF};
  1766. finally
  1767. json.Free;
  1768. end;
  1769. end;
  1770. function TJsonSerializer.ArrayToJsonString<T>(aArray: TArray<T>; aIndent: Boolean): string;
  1771. var
  1772. json: TJSONValue;
  1773. begin
  1774. {$IFDEF DEBUG_SERIALIZER}
  1775. TDebugger.TimeIt(Self,'ArrayToJsonString','');
  1776. {$ENDIF}
  1777. json:= fRTTIJson.SerializeValue(TValue.From<TArray<T>>(aArray));
  1778. if json = nil then raise EJsonSerializerError.Create('Error serializing Array');
  1779. try
  1780. if aIndent then Result := TJsonUtils.JsonFormat(json.ToString)
  1781. else Result := json.ToString;
  1782. finally
  1783. json.Free;
  1784. end;
  1785. end;
  1786. {$IFNDEF FPC}
  1787. function TJsonSerializer.JsonStreamToObject(aObject: TObject; aJsonStream: TStream): TObject;
  1788. var
  1789. json : string;
  1790. begin
  1791. {$IFDEF DEBUG_SERIALIZER}
  1792. TDebugger.TimeIt(Self,'JsonStreamToObject','');
  1793. {$ENDIF}
  1794. if aJsonStream = nil then raise EJsonDeserializeError.Create('JsonStream param cannot be nil!');
  1795. json := StreamToString(aJsonStream,TEncoding.UTF8);
  1796. Result := JsonToObject(aObject,json);
  1797. end;
  1798. function TJsonSerializer.JsonToArray<T>(const aJson: string): TArray<T>;
  1799. var
  1800. jarray: TJSONArray;
  1801. value : TValue;
  1802. begin;
  1803. {$IFDEF DEBUG_SERIALIZER}
  1804. TDebugger.TimeIt(Self,'JsonToArray','');
  1805. {$ENDIF}
  1806. try
  1807. {$If Defined(FPC) OR Defined(DELPHIRX10_UP)}
  1808. jarray := TJSONObject.ParseJSONValue(aJson,True) as TJSONArray;
  1809. {$ELSE}
  1810. jarray := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONArray;
  1811. {$ENDIF}
  1812. except
  1813. raise EJsonDeserializeError.Create(cNotValidJson);
  1814. end;
  1815. try
  1816. value := fRTTIJson.DeserializeDynArray(PTypeInfo(TypeInfo(TArray<T>)),nil,jarray);
  1817. Result := value.AsType<TArray<T>>;
  1818. finally
  1819. jarray.Free;
  1820. end;
  1821. end;
  1822. function TJsonSerializer.JsonToValue(const aJson: string): TValue;
  1823. var
  1824. json: TJSONObject;
  1825. value : TValue;
  1826. begin;
  1827. {$IFDEF DEBUG_SERIALIZER}
  1828. TDebugger.TimeIt(Self,'JsonToValue','');
  1829. {$ENDIF}
  1830. try
  1831. {$If Defined(FPC) OR Defined(DELPHIRX10_UP)}
  1832. json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
  1833. {$ELSE}
  1834. json := TJsonObject.ParseJSONValue(TEncoding.UTF8.GetBytes(aJson),0,True) as TJSONObject;
  1835. {$ENDIF}
  1836. except
  1837. raise EJsonDeserializeError.Create(cNotValidJson);
  1838. end;
  1839. try
  1840. value := fRTTIJson.DeserializeRecord(value,nil,json);
  1841. Result := value; // value.AsType<TArray<T>>;
  1842. finally
  1843. json.Free;
  1844. end;
  1845. end;
  1846. {$ENDIF}
  1847. procedure TJsonSerializer.SetSerializeLevel(const Value: TSerializeLevel);
  1848. begin
  1849. fSerializeLevel := Value;
  1850. if Assigned(fRTTIJson) then fRTTIJson.fSerializeLevel := Value;
  1851. end;
  1852. procedure TJsonSerializer.SetUseBase64Stream(const Value: Boolean);
  1853. begin
  1854. fUseBase64Stream := Value;
  1855. if Assigned(fRTTIJson) then fRTTIJson.UseBase64Stream := Value;
  1856. end;
  1857. procedure TJsonSerializer.SetUseEnumNames(const Value: Boolean);
  1858. begin
  1859. fUseEnumNames := Value;
  1860. if Assigned(fRTTIJson) then fRTTIJson.UseEnumNames := Value;
  1861. end;
  1862. procedure TJsonSerializer.SetUseJsonCaseSense(const Value: Boolean);
  1863. begin
  1864. fUseJsonCaseSense := Value;
  1865. if Assigned(fRTTIJson) then fRTTIJson.UseJsonCaseSense := Value;
  1866. end;
  1867. {$IFNDEF FPC}
  1868. { TCommentProperty }
  1869. constructor TCommentProperty.Create(const aComment: string);
  1870. begin
  1871. fComment := aComment;
  1872. end;
  1873. { TCustomNameProperty }
  1874. constructor TCustomNameProperty.Create(const aName: string);
  1875. begin
  1876. fName := aName;
  1877. end;
  1878. {$ENDIF}
  1879. {$IF NOT DEFINED(DELPHIXE7_UP) AND NOT DEFINED(FPC)}
  1880. { TJSONArrayHelper }
  1881. function TJSONArrayHelper.Count: Integer;
  1882. begin
  1883. Result := Self.Size;
  1884. end;
  1885. function TJSONArrayHelper.GetItem(aValue: Integer): TJSONValue;
  1886. begin
  1887. Result := Self.Get(aValue);
  1888. end;
  1889. procedure TJSONArrayHelper.SetElements(aElements: TList<TJSONValue>);
  1890. var
  1891. jvalue : TJSONValue;
  1892. begin
  1893. for jvalue in aElements do Self.AddElement(jvalue);
  1894. aElements.Free;
  1895. end;
  1896. { TJSONValueHelper }
  1897. function TJSONValueHelper.ToJson: string;
  1898. begin
  1899. Result := Self.ToString;
  1900. end;
  1901. { TJSONObjectHelper }
  1902. function TJSONObjectHelper.Count: Integer;
  1903. begin
  1904. Result := Self.Size;
  1905. end;
  1906. function TJSONObjectHelper.GetValue(const aName: string): TJSONValue;
  1907. var
  1908. jPair : TJSONPair;
  1909. begin
  1910. Result := nil;
  1911. for jPair in Self do
  1912. begin
  1913. if jPair.JsonString.ToString = aName then Exit(jPair.JsonValue);
  1914. end;
  1915. end;
  1916. function TJSONObjectHelper.GetPair(aValue: Integer) : TJSONPair;
  1917. begin
  1918. Result := Self.Get(aValue);
  1919. end;
  1920. {$ENDIF}
  1921. end.