Quick.Json.Serializer.pas 64 KB

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