Quick.Json.Serializer.pas 60 KB

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