Quick.Json.Serializer.pas 50 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601
  1. { ***************************************************************************
  2. Copyright (c) 2015-2019 Kike Pérez
  3. Unit : Quick.JSON.Serializer
  4. Description : Json Serializer
  5. Author : Kike Pérez
  6. Version : 1.8
  7. Created : 21/05/2018
  8. Modified : 12/04/2019
  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. Classes,
  26. SysUtils,
  27. Rtti,
  28. TypInfo,
  29. {$IFDEF FPC}
  30. rttiutils,
  31. fpjson,
  32. jsonparser,
  33. strUtils,
  34. //jsonreader,
  35. //fpjsonrtti,
  36. Quick.Json.fpc.Compatibility,
  37. {$ELSE}
  38. {$IFDEF DELPHIXE7_UP}
  39. System.Json,
  40. {$ENDIF}
  41. {$IFDEF DELPHIRX103_UP}
  42. System.Generics.Collections,
  43. {$ENDIF}
  44. {$ENDIF}
  45. DateUtils,
  46. Quick.Commons,
  47. Quick.JSON.Utils;
  48. type
  49. EJsonSerializeError = class(Exception);
  50. EJsonDeserializeError = class(Exception);
  51. {$IFNDEF FPC}
  52. TNotSerializableProperty = class(TCustomAttribute);
  53. TCommentProperty = class(TCustomAttribute)
  54. private
  55. fComment : string;
  56. public
  57. constructor Create(const aComment: string);
  58. property Comment : string read fComment;
  59. end;
  60. TCustomNameProperty = class(TCustomAttribute)
  61. private
  62. fName : string;
  63. public
  64. constructor Create(const aName: string);
  65. property Name : string read fName;
  66. end;
  67. {$ENDIF}
  68. IJsonSerializer = interface
  69. ['{CA26F7AE-F1FE-41BE-9C23-723A687F60D1}']
  70. function JsonToObject(aType: TClass; const aJson: string): TObject; overload;
  71. function JsonToObject(aObject: TObject; const aJson: string): TObject; overload;
  72. function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
  73. end;
  74. TSerializeLevel = (slPublicProperty, slPublishedProperty);
  75. TRTTIJson = class
  76. private
  77. fSerializeLevel : TSerializeLevel;
  78. fUseEnumNames : Boolean;
  79. fUseJsonCaseSense : Boolean;
  80. function GetValue(aAddr: Pointer; aType: TRTTIType): TValue; overload;
  81. function GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue; overload;
  82. function IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
  83. function IsGenericList(aObject : TObject) : Boolean;
  84. function IsGenericXArray(const aClassName : string) : Boolean;
  85. function GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
  86. function GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
  87. {$IFNDEF FPC}
  88. function GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
  89. {$ENDIF}
  90. procedure SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue); overload;
  91. procedure SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue); overload;
  92. {$IFDEF FPC}
  93. function FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
  94. function GetPropType(aPropInfo: PPropInfo): PTypeInfo;
  95. procedure LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
  96. {$ENDIF}
  97. public
  98. constructor Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
  99. property UseEnumNames : Boolean read fUseEnumNames write fUseEnumNames;
  100. property UseJsonCaseSense : Boolean read fUseJsonCaseSense write fUseJsonCaseSense;
  101. {$IFNDEF FPC}
  102. function DeserializeDynArray(aTypeInfo : PTypeInfo; aObject : TObject; const aJsonArray: TJSONArray) : TValue;
  103. function DeserializeRecord(aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
  104. {$ELSE}
  105. procedure DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aJsonArray: TJSONArray);
  106. {$ENDIF}
  107. function DeserializeClass(aType : TClass; const aJson : TJSONObject) : TObject;
  108. function DeserializeObject(aObject : TObject; const aJson : TJSONObject) : TObject; overload;
  109. {$IFNDEF FPC}
  110. function DeserializeList(aObject: TObject; const aName : string; const aJson: TJSONObject) : TObject;
  111. procedure DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aJson : TJsonObject);
  112. {$ENDIF}
  113. function DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject; overload;
  114. {$IFNDEF FPC}
  115. function DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
  116. {$ELSE}
  117. function DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
  118. {$ENDIF}
  119. {$IFNDEF FPC}
  120. function Serialize(const aName : string; aValue : TValue) : TJSONPair; overload;
  121. {$ELSE}
  122. function Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
  123. function Serialize(const aName : string; aValue : TValue) : TJSONPair;
  124. {$ENDIF}
  125. function Serialize(aObject : TObject) : TJSONObject; overload;
  126. function GetJsonPairByName(aJson : TJSONObject; const aName : string) : TJSONPair;
  127. end;
  128. TJsonSerializer = class(TInterfacedObject,IJsonSerializer)
  129. strict private
  130. fSerializeLevel : TSerializeLevel;
  131. fUseEnumNames : Boolean;
  132. fUseJsonCaseSense : Boolean;
  133. fRTTIJson : TRTTIJson;
  134. private
  135. procedure SetUseEnumNames(const Value: Boolean);
  136. procedure SetUseJsonCaseSense(const Value: Boolean);
  137. public
  138. constructor Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
  139. destructor Destroy; override;
  140. property SerializeLevel : TSerializeLevel read fSerializeLevel;
  141. property UseEnumNames : Boolean read fUseEnumNames write SetUseEnumNames;
  142. property UseJsonCaseSense : Boolean read fUseJsonCaseSense write SetUseJsonCaseSense;
  143. function JsonToObject(aType : TClass; const aJson: string) : TObject; overload;
  144. function JsonToObject(aObject : TObject; const aJson: string) : TObject; overload;
  145. function ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
  146. function ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
  147. end;
  148. PPByte = ^PByte;
  149. resourcestring
  150. cNotSupportedDataType = 'Not supported "%s" data type "%s"';
  151. cNotSerializable = 'Object is not serializable';
  152. implementation
  153. { TRTTIJson }
  154. {$IFNDEF FPC}
  155. function TRTTIJson.DeserializeDynArray(aTypeInfo: PTypeInfo; aObject: TObject; const aJsonArray: TJSONArray) : TValue;
  156. var
  157. rType: PTypeInfo;
  158. len: NativeInt;
  159. pArr: Pointer;
  160. rItemValue: TValue;
  161. i: Integer;
  162. objClass: TClass;
  163. ctx : TRttiContext;
  164. json : TJSONObject;
  165. rDynArray : TRttiDynamicArrayType;
  166. propObj : TObject;
  167. begin
  168. if GetTypeData(aTypeInfo).DynArrElType = nil then Exit;
  169. if not assigned(aJsonArray) then Exit;
  170. len := aJsonArray.Count;
  171. rType := GetTypeData(aTypeInfo).DynArrElType^;
  172. pArr := nil;
  173. DynArraySetLength(pArr,aTypeInfo, 1, @len);
  174. try
  175. TValue.Make(@pArr,aTypeInfo, Result);
  176. rDynArray := ctx.GetType(Result.TypeInfo) as TRTTIDynamicArrayType;
  177. for i := 0 to aJsonArray.Count - 1 do
  178. begin
  179. rItemValue := nil;
  180. case rType.Kind of
  181. tkClass :
  182. begin
  183. if aJsonArray.Items[i] is TJSONObject then
  184. begin
  185. propObj := GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).AsObject;
  186. if propObj = nil then
  187. begin
  188. objClass := rType.TypeData.ClassType;
  189. rItemValue := DeserializeClass(objClass, TJSONObject(aJsonArray.Items[i]));
  190. end
  191. else
  192. begin
  193. DeserializeObject(propObj,TJSONObject(aJsonArray.Items[i]));
  194. end;
  195. end;
  196. end;
  197. tkRecord :
  198. begin
  199. json := TJSONObject(aJsonArray.Items[i]);
  200. rItemValue := DeserializeRecord(GetValue(PPByte(Result.GetReferenceToRawData)^ +rDynArray.ElementType.TypeSize * i,
  201. rDynArray.ElementType),aObject,json);
  202. end;
  203. tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
  204. begin
  205. //skip these properties
  206. end
  207. else
  208. begin
  209. rItemValue := DeserializeType(aObject,rType.Kind,aTypeInfo,aJsonArray.Items[i].Value);
  210. end;
  211. end;
  212. if not rItemValue.IsEmpty then Result.SetArrayElement(i,rItemValue);
  213. end;
  214. //aProperty.SetValue(aObject,rValue);
  215. finally
  216. DynArrayClear(pArr,aTypeInfo);
  217. end;
  218. end;
  219. {$ELSE}
  220. procedure TRTTIJson.DeserializeDynArray(aTypeInfo: PTypeInfo; const aPropertyName : string; aObject: TObject; const aJsonArray: TJSONArray);
  221. var
  222. rType: PTypeInfo;
  223. len: NativeInt;
  224. pArr: Pointer;
  225. rItemValue: TValue;
  226. i: Integer;
  227. objClass: TClass;
  228. propObj : TObject;
  229. rValue : TValue;
  230. begin
  231. if GetTypeData(aTypeInfo).ElType2 = nil then Exit;
  232. len := aJsonArray.Count;
  233. rType := GetTypeData(aTypeInfo).ElType2;
  234. pArr := nil;
  235. DynArraySetLength(pArr,aTypeInfo, 1, @len);
  236. try
  237. TValue.Make(@pArr,aTypeInfo, rValue);
  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(rValue.GetReferenceToRawData)^ +GetTypeData(aTypeInfo).elSize * i, GetTypeData(aTypeInfo).ElType2).AsObject;
  247. if propObj = nil then
  248. begin
  249. objClass := GetTypeData(aTypeInfo).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,GetTypeData(aTypeInfo).ElType2.Kind,aPropertyName,aJsonArray.Items[i].Value);
  271. end;
  272. end;
  273. if not rItemValue.IsEmpty then rValue.SetArrayElement(i,rItemValue);
  274. end;
  275. //aProperty.SetValue(aObject,rValue);
  276. SetDynArrayProp(aObject,GetPropInfo(aObject,aPropertyName),pArr);
  277. finally
  278. DynArrayClear(pArr,aTypeInfo);
  279. end;
  280. end;
  281. {$ENDIF}
  282. {$IFNDEF FPC}
  283. function TRTTIJson.DeserializeRecord(aRecord : TValue; aObject : TObject; const aJson : TJSONObject) : TValue;
  284. var
  285. ctx : TRttiContext;
  286. rRec : TRttiRecordType;
  287. rField : TRttiField;
  288. rValue : TValue;
  289. member : TJSONPair;
  290. jArray : TJSONArray;
  291. json : TJSONObject;
  292. objClass : TClass;
  293. propobj : TObject;
  294. begin
  295. rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
  296. try
  297. for rField in rRec.GetFields do
  298. begin
  299. rValue := nil;
  300. //member := TJSONPair(aJson.GetValue(rField.Name));
  301. member := GetJsonPairByName(aJson,rField.Name);
  302. if member <> nil then
  303. case rField.FieldType.TypeKind of
  304. tkDynArray :
  305. begin
  306. jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
  307. try
  308. rValue := DeserializeDynArray(rField.FieldType.Handle,aObject,jArray);
  309. finally
  310. jArray.Free;
  311. end;
  312. end;
  313. tkClass :
  314. begin
  315. //if (member.JsonValue is TJSONObject) then
  316. begin
  317. propobj := rField.GetValue(@aRecord).AsObject;
  318. json := TJSONObject.ParseJSONValue(member.ToJson) as TJSONObject;
  319. try
  320. if propobj = nil then
  321. begin
  322. objClass := rField.FieldType.Handle^.TypeData.ClassType;// aProperty.PropertyType.Handle^.TypeData.ClassType;
  323. rValue := DeserializeClass(objClass,json);
  324. end
  325. else
  326. begin
  327. DeserializeObject(propobj,json);
  328. end;
  329. finally
  330. json.Free;
  331. end;
  332. end
  333. end;
  334. tkRecord :
  335. begin
  336. json := TJSONObject.ParseJSONValue(member.ToJson) as TJSONObject;
  337. try
  338. rValue := DeserializeRecord(rField.GetValue(aRecord.GetReferenceToRawData),aObject,json);
  339. finally
  340. json.Free;
  341. end;
  342. end
  343. else
  344. begin
  345. //rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.ToJson);
  346. //avoid return unicode escaped chars if string
  347. if rField.FieldType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
  348. {$IFDEF DELPHIRX103_UP}
  349. rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,TJsonValue(member).value)
  350. {$ELSE}
  351. rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.JsonString.ToString)
  352. {$ENDIF}
  353. else rValue := DeserializeType(aObject,rField.FieldType.TypeKind,rField.FieldType.Handle,member.ToJSON);
  354. end;
  355. end;
  356. if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
  357. end;
  358. Result := aRecord;
  359. finally
  360. ctx.Free;
  361. end;
  362. end;
  363. {$ENDIF}
  364. constructor TRTTIJson.Create(aSerializeLevel : TSerializeLevel; aUseEnumNames : Boolean = True);
  365. begin
  366. fSerializeLevel := aSerializeLevel;
  367. fUseEnumNames := aUseEnumNames;
  368. fUseJsonCaseSense := False;
  369. end;
  370. function TRTTIJson.DeserializeClass(aType: TClass; const aJson: TJSONObject): TObject;
  371. begin
  372. Result := nil;
  373. if (aJson = nil) or ((aJson as TJSONValue) is TJSONNull) or (aJson.Count = 0) then Exit;
  374. Result := aType.Create;
  375. try
  376. Result := DeserializeObject(Result,aJson);
  377. except
  378. on E : Exception do
  379. begin
  380. Result.Free;
  381. raise EJsonDeserializeError.CreateFmt('Deserialize error class "%s" : %s',[aType.ClassName,e.Message]);
  382. end;
  383. end;
  384. end;
  385. function TRTTIJson.DeserializeObject(aObject: TObject; const aJson: TJSONObject): TObject;
  386. var
  387. ctx: TRttiContext;
  388. rType: TRttiType;
  389. rProp: TRttiProperty;
  390. {$IFNDEF FPC}
  391. attr: TCustomAttribute;
  392. {$ENDIF}
  393. propertyname : string;
  394. begin
  395. Result := aObject;
  396. if (aJson = nil) or ((aJson as TJSONValue) is TJSONNull) or (aJson.Count = 0) or (Result = nil) then Exit;
  397. try
  398. rType := ctx.GetType(aObject.ClassInfo);
  399. try
  400. for rProp in rType.GetProperties do
  401. begin
  402. {$IFNDEF FPC}
  403. if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
  404. or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
  405. {$ENDIF}
  406. begin
  407. if ((rProp.IsWritable) or (rProp.Name = 'List')) and (IsAllowedProperty(aObject,rProp.Name)) then
  408. begin
  409. propertyname := rProp.Name;
  410. {$IFNDEF FPC}
  411. for attr in rProp.GetAttributes do if attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
  412. if rProp.Name = 'List' then
  413. begin
  414. Result := DeserializeList(Result,propertyname,aJson);
  415. end
  416. else if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
  417. begin
  418. DeserializeList(rProp.GetValue(aObject).AsObject,'List',TJSONObject(aJson.GetValue(propertyname)));
  419. end
  420. else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
  421. begin
  422. DeserializeXArray(Result,rProp.GetValue(aObject),rProp,propertyname,aJson);
  423. end
  424. else
  425. {$ENDIF}
  426. Result := DeserializeProperty(Result,propertyname,rProp,aJson);
  427. end;
  428. end;
  429. end;
  430. finally
  431. ctx.Free;
  432. end;
  433. except
  434. on E : Exception do
  435. begin
  436. Result.Free;
  437. raise EJsonDeserializeError.CreateFmt('Deserialize error for object "%s" : %s',[aObject.ClassName,e.Message]);
  438. end;
  439. end;
  440. end;
  441. {$IFNDEF FPC}
  442. function TRTTIJson.DeserializeList(aObject: TObject; const aName : string; const aJson: TJSONObject) : TObject;
  443. var
  444. ctx : TRttiContext;
  445. rType : TRttiType;
  446. jarray : TJSONArray;
  447. member : TJSONPair;
  448. rvalue : TValue;
  449. i : Integer;
  450. rProp : TRttiProperty;
  451. {$IFNDEF DELPHIRX103_UP}
  452. rfield : TRttiField;
  453. {$ENDIF}
  454. begin
  455. Result := aObject;
  456. rType := ctx.GetType(aObject.ClassInfo);
  457. try
  458. rProp := rType.GetProperty('List');
  459. if rProp = nil then Exit;
  460. finally
  461. ctx.Free;
  462. end;
  463. member := GetJsonPairByName(aJson,aName);
  464. if member = nil then jArray := TJSONObject.ParseJSONValue(aJson.ToJSON) as TJSONArray
  465. else jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
  466. try
  467. rvalue := DeserializeDynArray(rProp.PropertyType.Handle,Result,jArray);
  468. //i := jarray.Count;
  469. finally
  470. jArray.Free;
  471. end;
  472. if not rValue.IsEmpty then
  473. begin
  474. {$IFDEF DELPHIRX103_UP}
  475. if (TObjectList<TObject>(aObject) <> nil) and (rvalue.IsArray) then
  476. begin
  477. TObjectList<TObject>(aObject).Clear;
  478. for i := 0 to rvalue.GetArrayLength - 1 do
  479. begin
  480. TObjectList<TObject>(aObject).Add(rvalue.GetArrayElement(i).AsObject);
  481. end;
  482. end;
  483. {$ELSE}
  484. for rfield in rType.GetFields do
  485. begin
  486. if rfield.Name = 'FOwnsObjects' then rfield.SetValue(aObject,True);
  487. //if rfield.Name = 'FCount' then rfield.SetValue(aObject,i);
  488. if rfield.Name = 'FItems' then
  489. begin
  490. //if TList(aObject) <> nil then TList(aObject).Clear;
  491. //rfield.GetValue(aObject).AsObject.Free;// aValue.GetReferenceToRawData)
  492. rfield.SetValue(aObject,rValue);// .SetDynArrayProp(aObject,'fItems',Result);
  493. Break;
  494. end;
  495. end;
  496. rProp := rType.GetProperty('Count');
  497. rProp.SetValue(aObject,i);
  498. {$ENDIF}
  499. end;
  500. end;
  501. {$ENDIF}
  502. {$IFNDEF FPC}
  503. procedure TRTTIJson.DeserializeXArray(Instance : TObject; aRecord : TValue; aProperty : TRttiProperty; const aPropertyName : string; aJson : TJsonObject);
  504. var
  505. ctx : TRttiContext;
  506. rRec : TRttiRecordType;
  507. rfield : TRttiField;
  508. rValue : TValue;
  509. member : TJSONPair;
  510. jArray : TJSONArray;
  511. begin
  512. rRec := ctx.GetType(aRecord.TypeInfo).AsRecord;
  513. try
  514. rfield := rRec.GetField('fArray');
  515. if rfield <> nil then
  516. begin
  517. rValue := nil;
  518. //member := TJSONPair(aJson.GetValue(rField.Name));
  519. member := GetJsonPairByName(aJson,aPropertyName);
  520. if (member <> nil) and (rField.FieldType.TypeKind = tkDynArray) then
  521. begin
  522. jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
  523. try
  524. rValue := DeserializeDynArray(rField.FieldType.Handle,nil,jArray);
  525. finally
  526. jArray.Free;
  527. end;
  528. end;
  529. end;
  530. if not rValue.IsEmpty then rField.SetValue(aRecord.GetReferenceToRawData,rValue);
  531. aProperty.SetValue(Instance,aRecord);
  532. finally
  533. ctx.Free;
  534. end;
  535. end;
  536. {$ENDIF}
  537. function TRTTIJson.DeserializeProperty(aObject : TObject; const aName : string; aProperty : TRttiProperty; const aJson : TJSONObject) : TObject;
  538. var
  539. rValue : TValue;
  540. {$IFNDEF FPC}
  541. member : TJSONPair;
  542. {$ELSE}
  543. member : TJsonObject;
  544. {$ENDIF}
  545. objClass: TClass;
  546. jArray : TJSONArray;
  547. json : TJSONObject;
  548. begin
  549. Result := aObject;
  550. rValue := nil;
  551. {$IFNDEF FPC}
  552. //member := TJSONPair(aJson.GetValue(aName));
  553. member := GetJsonPairByName(aJson,aName);
  554. {$ELSE}
  555. member := TJsonObject(aJson.Find(aName));
  556. {$ENDIF}
  557. if member <> nil then
  558. begin
  559. case aProperty.PropertyType.TypeKind of
  560. tkDynArray :
  561. begin
  562. {$IFNDEF FPC}
  563. jArray := TJSONObject.ParseJSONValue(member.ToJSON) as TJSONArray;
  564. {$ELSE}
  565. jArray := TJSONArray(TJSONObject.ParseJSONValue(member.ToJSON));
  566. {$ENDIF}
  567. try
  568. {$IFNDEF FPC}
  569. aProperty.SetValue(aObject,DeserializeDynArray(aProperty.PropertyType.Handle,Result,jArray));
  570. {$ELSE}
  571. DeserializeDynArray(aProperty.PropertyType.Handle,aName,Result,jArray);
  572. {$ENDIF}
  573. Exit;
  574. finally
  575. jArray.Free;
  576. end;
  577. end;
  578. tkClass :
  579. begin
  580. //if (member.JsonValue is TJSONObject) then
  581. begin
  582. json := TJsonObject(TJSONObject.ParseJSONValue(member.ToJson));
  583. try
  584. if aProperty.GetValue(aObject).AsObject = nil then
  585. begin
  586. {$IFNDEF FPC}
  587. objClass := aProperty.PropertyType.Handle^.TypeData.ClassType;
  588. rValue := DeserializeClass(objClass,json);
  589. {$ELSE}
  590. objClass := GetObjectPropClass(aObject,aName);
  591. //objClass := GetTypeData(aProperty.PropertyType.Handle)^.ClassType;
  592. rValue := DeserializeClass(objClass,json);
  593. SetObjectProp(aObject,aName,rValue.AsObject);
  594. Exit;
  595. {$ENDIF}
  596. end
  597. else
  598. begin
  599. rValue := DeserializeObject(aProperty.GetValue(aObject).AsObject,json);
  600. Exit;
  601. end;
  602. finally
  603. json.Free;
  604. end;
  605. end
  606. end;
  607. {$IFNDEF FPC}
  608. tkRecord :
  609. begin
  610. json := TJSONObject.ParseJSONValue(member.ToJson) as TJSONObject;
  611. try
  612. rValue := DeserializeRecord(aProperty.GetValue(aObject),aObject,json);
  613. finally
  614. json.Free;
  615. end;
  616. end;
  617. {$ENDIF}
  618. else
  619. begin
  620. {$IFNDEF FPC}
  621. //avoid return unicode escaped chars if string
  622. if aProperty.PropertyType.TypeKind in [tkString, tkLString, tkWString, tkUString] then
  623. {$IFDEF DELPHIRX103_UP}
  624. rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,TJsonValue(member).value)
  625. {$ELSE}
  626. rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.JsonString.ToString)
  627. {$ENDIF}
  628. else rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aProperty.GetValue(aObject).TypeInfo,member.ToJSON);
  629. {$ELSE}
  630. rValue := DeserializeType(aObject,aProperty.PropertyType.TypeKind,aName,member.ToJSON);
  631. if not rValue.IsEmpty then SetPropertyValue(aObject,aName,rValue);
  632. {$ENDIF}
  633. end;
  634. end;
  635. {$IFNDEF FPC}
  636. if not rValue.IsEmpty then aProperty.SetValue(Result,rValue);
  637. {$ENDIF}
  638. end;
  639. end;
  640. {$IFNDEF FPC}
  641. function TRTTIJson.DeserializeType(aObject : TObject; aType : TTypeKind; aTypeInfo : PTypeInfo; const aValue: string) : TValue;
  642. var
  643. i : Integer;
  644. value : string;
  645. fsettings : TFormatSettings;
  646. begin
  647. try
  648. value := AnsiDequotedStr(aValue,'"');
  649. case aType of
  650. tkString, tkLString, tkWString, tkUString :
  651. begin
  652. Result := value;
  653. end;
  654. tkChar, tkWChar :
  655. begin
  656. Result := value;
  657. end;
  658. tkInteger :
  659. begin
  660. Result := StrToInt(value);
  661. end;
  662. tkInt64 :
  663. begin
  664. Result := StrToInt64(value);
  665. end;
  666. tkFloat :
  667. begin
  668. if aTypeInfo = TypeInfo(TDateTime) then
  669. begin
  670. Result := JsonDateToDateTime(value);
  671. end
  672. else if aTypeInfo = TypeInfo(TDate) then
  673. begin
  674. Result := StrToDate(value);
  675. end
  676. else if aTypeInfo = TypeInfo(TTime) then
  677. begin
  678. Result := StrToTime(value);
  679. end
  680. else
  681. begin
  682. fsettings := TFormatSettings.Create;
  683. Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
  684. end;
  685. end;
  686. tkEnumeration :
  687. begin
  688. if aTypeInfo = System.TypeInfo(Boolean) then
  689. begin
  690. Result := StrToBool(value);
  691. end
  692. else
  693. begin
  694. //if fUseEnumNames then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
  695. // else TValue.Make(StrToInt(value),aTypeInfo, Result);
  696. if not TryStrToInt(value,i) then TValue.Make(GetEnumValue(aTypeInfo,value),aTypeInfo, Result)
  697. else TValue.Make(StrToInt(value),aTypeInfo, Result);
  698. end;
  699. end;
  700. tkSet :
  701. begin
  702. i := StringToSet(aTypeInfo,value);
  703. TValue.Make(@i,aTypeInfo,Result);
  704. end;
  705. else
  706. begin
  707. //raise EclJsonSerializerError.Create('Not supported data type!');
  708. end;
  709. end;
  710. except
  711. on E : Exception do
  712. begin
  713. raise EJsonDeserializeError.CreateFmt('Deserialize error type "%s.%s" : %s',[aObject.ClassName,GetTypeName(aTypeInfo),e.Message]);
  714. end;
  715. end;
  716. end;
  717. {$ELSE}
  718. function TRTTIJson.DeserializeType(aObject : TObject; aType : TTypeKind; const aPropertyName, aValue: string) : TValue;
  719. var
  720. value : string;
  721. propinfo : PPropInfo;
  722. fsettings : TFormatSettings;
  723. begin
  724. try
  725. value := AnsiDequotedStr(aValue,'"');
  726. if value = '' then
  727. begin
  728. Result := nil;
  729. Exit;
  730. end;
  731. propinfo := GetPropInfo(aObject,aPropertyName);
  732. //case propinfo.PropType.Kind of
  733. case aType of
  734. tkString, tkLString, tkWString, tkUString, tkAString :
  735. begin
  736. Result := value;
  737. //SetStrProp(aObject,propinfo,value);
  738. end;
  739. tkChar, tkWChar :
  740. begin
  741. Result := value;
  742. end;
  743. tkInteger :
  744. begin
  745. Result := StrToInt(value);
  746. end;
  747. tkInt64 :
  748. begin
  749. Result := StrToInt64(value);
  750. end;
  751. tkFloat :
  752. begin
  753. if propinfo.PropType = TypeInfo(TDateTime) then
  754. begin
  755. Result := JsonDateToDateTime(value);
  756. end
  757. else if propinfo.PropType = TypeInfo(TDate) then
  758. begin
  759. Result := StrToDate(value);
  760. end
  761. else if propinfo.PropType = TypeInfo(TTime) then
  762. begin
  763. Result := StrToTime(value);
  764. end
  765. else
  766. begin
  767. fsettings := DefaultFormatSettings;
  768. Result := StrToFloat(StringReplace(value,'.',fsettings.DecimalSeparator,[]));
  769. end;
  770. end;
  771. tkEnumeration:
  772. begin
  773. Result := value;
  774. end;
  775. tkBool :
  776. begin
  777. Result := StrToBool(value);
  778. end;
  779. tkSet :
  780. begin
  781. Result := value;
  782. end;
  783. else
  784. begin
  785. //raise EclJsonSerializerError.Create('Not supported data type!');
  786. end;
  787. end;
  788. //if not Result.IsEmpty then SetPropertyValue(aObject,propinfo,Result);
  789. except
  790. on E : Exception do
  791. begin
  792. raise EJsonDeserializeError.CreateFmt('Deserialize error type "%s" : %s',[aObject.ClassName,e.Message]);
  793. end;
  794. end;
  795. end;
  796. {$ENDIF}
  797. function TRTTIJson.IsAllowedProperty(aObject : TObject; const aPropertyName : string) : Boolean;
  798. var
  799. propname : string;
  800. begin
  801. Result := True;
  802. propname := aPropertyName.ToLower;
  803. if IsGenericList(aObject) then
  804. begin
  805. if (propname = 'capacity') or (propname = 'count') or (propname = 'ownsobjects') then Result := False;
  806. end
  807. else if (propname = 'refcount') then Result := False;
  808. end;
  809. function TRTTIJson.IsGenericList(aObject : TObject) : Boolean;
  810. var
  811. cname : string;
  812. begin
  813. if aObject = nil then Exit(False);
  814. cname := aObject.ClassName;
  815. Result := (cname.StartsWith('TObjectList')) or (cname.StartsWith('TList'));
  816. end;
  817. function TRTTIJson.IsGenericXArray(const aClassName : string) : Boolean;
  818. begin
  819. Result := aClassName.StartsWith('TXArray');
  820. end;
  821. function TRTTIJson.GetJsonPairByName(aJson: TJSONObject; const aName: string): TJSONPair;
  822. var
  823. candidate : TJSONPair;
  824. i : Integer;
  825. begin
  826. if fUseJsonCaseSense then
  827. begin
  828. Result := TJSONPair(aJson.GetValue(aName));
  829. Exit;
  830. end
  831. else
  832. begin
  833. for i := 0 to aJson.Count - 1 do
  834. begin
  835. candidate := aJson.Pairs[I];
  836. if candidate.JsonValue = nil then Exit(nil);
  837. if CompareText(candidate.JsonString{$IFNDEF FPC}.Value{$ENDIF},aName) = 0 then
  838. Exit(TJsonPair(candidate.JsonValue));
  839. end;
  840. end;
  841. Result := nil;
  842. end;
  843. function TRTTIJson.GetPropertyValue(Instance : TObject; const PropertyName : string) : TValue;
  844. var
  845. pinfo : PPropInfo;
  846. begin
  847. Result := nil;
  848. pinfo := GetPropInfo(Instance,PropertyName);
  849. case pinfo.PropType^.Kind of
  850. tkInteger : Result := GetOrdProp(Instance,pinfo);
  851. tkInt64 : Result := GetInt64Prop(Instance,PropertyName);
  852. tkFloat : Result := GetFloatProp(Instance,PropertyName);
  853. tkChar : Result := Char(GetOrdProp(Instance,PropertyName));
  854. {$IFDEF FPC}
  855. tkWString : Result := GetWideStrProp(Instance,PropertyName);
  856. tkSString,
  857. tkAString,
  858. {$ELSE}
  859. tkWString,
  860. {$ENDIF}
  861. tkLString : Result := GetStrProp(Instance,pinfo);
  862. {$IFDEF FPC}
  863. tkEnumeration :
  864. begin
  865. if fUseEnumNames then Result := GetEnumName(pinfo.PropType,GetOrdProp(Instance,PropertyName))
  866. else Result := GetOrdProp(Instance,PropertyName);
  867. end;
  868. {$ELSE}
  869. tkEnumeration :
  870. begin
  871. if fUseEnumNames then Result := GetEnumName(@pinfo.PropType,GetOrdProp(Instance,PropertyName))
  872. else Result := GetOrdProp(Instance,PropertyName);
  873. end;
  874. {$ENDIF}
  875. tkSet : Result := GetSetProp(Instance,pinfo,True);
  876. {$IFNDEF FPC}
  877. tkClass :
  878. {$ELSE}
  879. tkBool : Result := Boolean(GetOrdProp(Instance,pinfo));
  880. tkObject :
  881. {$ENDIF} Result := GetObjectProp(Instance,pinfo);
  882. tkDynArray : Result := GetDynArrayProp(Instance,pinfo);
  883. end;
  884. end;
  885. function TRTTIJson.GetPropertyValueFromObject(Instance : TObject; const PropertyName : string) : TValue;
  886. var
  887. ctx : TRttiContext;
  888. rprop : TRttiProperty;
  889. begin
  890. rprop := ctx.GetType(Instance.ClassInfo).GetProperty(PropertyName);
  891. Result := rprop.GetValue(Instance);
  892. end;
  893. {$IFNDEF FPC}
  894. function TRTTIJson.GetFieldValueFromRecord(aValue : TValue; const FieldName : string) : TValue;
  895. var
  896. ctx : TRttiContext;
  897. rec : TRttiRecordType;
  898. rfield : TRttiField;
  899. begin
  900. rec := ctx.GetType(aValue.TypeInfo).AsRecord;
  901. rfield := rec.GetField(FieldName);
  902. if rfield <> nil then Result := rField.GetValue(aValue.GetReferenceToRawData)
  903. else Result := nil;
  904. end;
  905. {$ENDIF}
  906. procedure TRTTIJson.SetPropertyValue(Instance : TObject; const PropertyName : string; aValue : TValue);
  907. var
  908. pinfo : PPropInfo;
  909. begin
  910. pinfo := GetPropInfo(Instance,PropertyName);
  911. SetPropertyValue(Instance,pinfo,aValue);
  912. end;
  913. procedure TRTTIJson.SetPropertyValue(Instance : TObject; aPropInfo : PPropInfo; aValue : TValue);
  914. begin
  915. case aPropInfo.PropType^.Kind of
  916. tkInteger : SetOrdProp(Instance,aPropInfo,aValue.AsInteger);
  917. tkInt64 : SetInt64Prop(Instance,aPropInfo,aValue.AsInt64);
  918. tkFloat : SetFloatProp(Instance,aPropInfo,aValue.AsExtended);
  919. tkChar : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
  920. {$IFDEF FPC}
  921. tkWString : SetWideStrProp(Instance,aPropInfo,aValue.AsString);
  922. tkSString,
  923. tkAString,
  924. {$ELSE}
  925. tkWString,
  926. {$ENDIF}
  927. tkLString : SetStrProp(Instance,aPropInfo,aValue.AsString);
  928. {$IFDEF FPC}
  929. tkBool : SetOrdProp(Instance,aPropInfo,aValue.AsOrdinal);
  930. tkSet : LoadSetProperty(Instance,aPropInfo,aValue.AsString);
  931. {$ENDIF}
  932. tkEnumeration : SetEnumProp(Instance,aPropInfo,aValue.AsString);
  933. {$IFNDEF FPC}
  934. tkClass :
  935. {$ELSE}
  936. tkObject :
  937. {$ENDIF} SetObjectProp(Instance,aPropInfo,aValue.AsObject);
  938. end;
  939. end;
  940. {$IFDEF FPC}
  941. procedure TRTTIJson.LoadSetProperty(aInstance : TObject; aPropInfo: PPropInfo; const aValue: string);
  942. type
  943. TCardinalSet = set of 0..SizeOf(Cardinal) * 8 - 1;
  944. const
  945. Delims = [' ', ',', '[', ']'];
  946. var
  947. TypeInfo: PTypeInfo;
  948. W: Cardinal;
  949. I, N: Integer;
  950. Count: Integer;
  951. EnumName: string;
  952. begin
  953. W := 0;
  954. TypeInfo := GetTypeData(GetPropType(aPropInfo))^.CompType;
  955. Count := WordCount(aValue, Delims);
  956. for N := 1 to Count do
  957. begin
  958. EnumName := ExtractWord(N, aValue, Delims);
  959. try
  960. I := GetEnumValue(TypeInfo, EnumName);
  961. if I >= 0 then Include(TCardinalSet(W),I);
  962. except
  963. end;
  964. end;
  965. SetOrdProp(aInstance,aPropInfo,W);
  966. end;
  967. {$ENDIF}
  968. function TRTTIJson.Serialize(aObject: TObject): TJSONObject;
  969. var
  970. ctx: TRttiContext;
  971. {$IFNDEF FPC}
  972. attr : TCustomAttribute;
  973. comment : string;
  974. {$ENDIF}
  975. rType: TRttiType;
  976. rProp: TRttiProperty;
  977. jpair : TJSONPair;
  978. ExcludeSerialize : Boolean;
  979. propertyname : string;
  980. //listtype : TRttiType;
  981. //listprop : TRttiProperty;
  982. //listvalue : TValue;
  983. begin
  984. if (aObject = nil) then
  985. begin
  986. Result := nil;
  987. Exit;
  988. end;
  989. Result := TJSONObject.Create;
  990. try
  991. rType := ctx.GetType(aObject.ClassInfo);
  992. try
  993. //s := rType.ToString;
  994. for rProp in rType.GetProperties do
  995. begin
  996. ExcludeSerialize := False;
  997. propertyname := rProp.Name;
  998. {$IFNDEF FPC}
  999. comment := '';
  1000. for attr in rProp.GetAttributes do
  1001. begin
  1002. if attr is TNotSerializableProperty then ExcludeSerialize := True
  1003. else if attr is TCommentProperty then comment := TCommentProperty(attr).Comment
  1004. else if attr is TCustomNameProperty then propertyname := TCustomNameProperty(attr).Name;
  1005. end;
  1006. if ((fSerializeLevel = slPublicProperty) and (rProp.PropertyType.IsPublicType))
  1007. or ((fSerializeLevel = slPublishedProperty) and ((IsPublishedProp(aObject,rProp.Name)) or (rProp.Name = 'List'))) then
  1008. {$ENDIF}
  1009. begin
  1010. if (IsAllowedProperty(aObject,propertyname)) and (not ExcludeSerialize) then
  1011. begin
  1012. //add comment as pair
  1013. {$IFNDEF FPC}
  1014. if comment <> '' then Result.AddPair(TJSONPair.Create('#Comment#->'+propertyname,Comment));
  1015. {$ENDIF}
  1016. begin
  1017. if (rProp.GetValue(aObject).IsObject) and (IsGenericList(rProp.GetValue(aObject).AsObject)) then
  1018. begin
  1019. jpair := Serialize(propertyname,GetPropertyValueFromObject(rProp.GetValue(aObject).AsObject,'List'));
  1020. end
  1021. {$IFNDEF FPC}
  1022. else if (not rProp.GetValue(aObject).IsObject) and (IsGenericXArray(rProp.GetValue(aObject){$IFNDEF NEXTGEN}.TypeInfo.Name{$ELSE}.TypeInfo.NameFld.ToString{$ENDIF})) then
  1023. begin
  1024. jpair := Serialize(propertyname,GetFieldValueFromRecord(rProp.GetValue(aObject),'fArray'));
  1025. end
  1026. {$ENDIF}
  1027. else
  1028. begin
  1029. {$IFNDEF FPC}
  1030. jpair := Serialize(propertyname,rProp.GetValue(aObject));
  1031. {$ELSE}
  1032. jpair := Serialize(aObject,rProp.PropertyType.TypeKind,propertyname);
  1033. {$ENDIF}
  1034. end;
  1035. //s := jpair.JsonValue.ToString;
  1036. if jpair <> nil then
  1037. begin
  1038. Result.AddPair(jpair);
  1039. end
  1040. else jpair.Free;
  1041. end;
  1042. //Result.AddPair(Serialize(rProp.Name,rProp.GetValue(aObject)));
  1043. //s := Result.ToJSON;
  1044. end;
  1045. end;
  1046. end;
  1047. finally
  1048. ctx.Free;
  1049. end;
  1050. except
  1051. on E : Exception do
  1052. begin
  1053. Result.Free;
  1054. raise EJsonSerializeError.CreateFmt('Serialize error object "%s" : %s',[aObject.ClassName,e.Message]);
  1055. end;
  1056. end;
  1057. end;
  1058. function TRTTIJson.GetValue(aAddr: Pointer; aType: TRTTIType): TValue;
  1059. begin
  1060. TValue.Make(aAddr,aType.Handle,Result);
  1061. end;
  1062. function TRTTIJson.GetValue(aAddr: Pointer; aTypeInfo: PTypeInfo): TValue;
  1063. begin
  1064. TValue.Make(aAddr,aTypeInfo,Result);
  1065. end;
  1066. {$IFNDEF FPC}
  1067. function TRTTIJson.Serialize(const aName : string; aValue : TValue) : TJSONPair;
  1068. var
  1069. ctx: TRttiContext;
  1070. rRec : TRttiRecordType;
  1071. rField : TRttiField;
  1072. rDynArray : TRTTIDynamicArrayType;
  1073. json : TJSONObject;
  1074. jArray : TJSONArray;
  1075. jPair : TJSONPair;
  1076. jValue : TJSONValue;
  1077. i : Integer;
  1078. begin
  1079. Result := TJSONPair.Create(aName,nil);
  1080. //Result.JsonString := TJSONString(aName);
  1081. try
  1082. case avalue.Kind of
  1083. tkDynArray :
  1084. begin
  1085. jArray := TJSONArray.Create;
  1086. rDynArray := ctx.GetType(aValue.TypeInfo) as TRTTIDynamicArrayType;
  1087. try
  1088. for i := 0 to aValue.GetArrayLength - 1 do
  1089. begin
  1090. if not GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType).IsEmpty then
  1091. begin
  1092. jValue := nil;
  1093. jPair := Serialize(aName,GetValue(PPByte(aValue.GetReferenceToRawData)^ + rDynArray.ElementType.TypeSize * i, rDynArray.ElementType));
  1094. try
  1095. //jValue := TJsonValue(jPair.JsonValue.Clone);
  1096. jValue := jPair.JsonValue;
  1097. if jValue <> nil then
  1098. begin
  1099. jArray.AddElement(jValue);
  1100. jPair.JsonValue.Owned := False;
  1101. end;
  1102. finally
  1103. jPair.Free;
  1104. if jValue <> nil then jValue.Owned := True;
  1105. end;
  1106. end;
  1107. end;
  1108. Result.JsonValue := jArray;
  1109. finally
  1110. ctx.Free;
  1111. end;
  1112. end;
  1113. tkClass :
  1114. begin
  1115. Result.JsonValue := TJSONValue(Serialize(aValue.AsObject));
  1116. end;
  1117. tkString, tkLString, tkWString, tkUString :
  1118. begin
  1119. Result.JsonValue := TJSONString.Create(aValue.AsString);
  1120. end;
  1121. tkChar, tkWChar :
  1122. begin
  1123. Result.JsonValue := TJSONString.Create(aValue.AsString);
  1124. end;
  1125. tkInteger :
  1126. begin
  1127. Result.JsonValue := TJSONNumber.Create(aValue.AsInteger);
  1128. end;
  1129. tkInt64 :
  1130. begin
  1131. Result.JsonValue := TJSONNumber.Create(aValue.AsInt64);
  1132. end;
  1133. tkFloat :
  1134. begin
  1135. if aValue.TypeInfo = TypeInfo(TDateTime) then
  1136. begin
  1137. Result.JsonValue := TJSONString.Create(DateTimeToJsonDate(aValue.AsExtended));
  1138. end
  1139. else if aValue.TypeInfo = TypeInfo(TDate) then
  1140. begin
  1141. Result.JsonValue := TJSONString.Create(DateToStr(aValue.AsExtended));
  1142. end
  1143. else if aValue.TypeInfo = TypeInfo(TTime) then
  1144. begin
  1145. Result.JsonValue := TJSONString.Create(TimeToStr(aValue.AsExtended));
  1146. end
  1147. else
  1148. begin
  1149. Result.JsonValue := TJSONNumber.Create(aValue.AsExtended);
  1150. end;
  1151. end;
  1152. tkEnumeration :
  1153. begin
  1154. if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
  1155. begin
  1156. Result.JsonValue := TJSONBool.Create(aValue.AsBoolean);
  1157. end
  1158. else
  1159. begin
  1160. //Result.JsonValue := TJSONString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
  1161. if fUseEnumNames then Result.JsonValue := TJSONString.Create(aValue.ToString)
  1162. else Result.JsonValue := TJSONNumber.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
  1163. end;
  1164. end;
  1165. tkSet :
  1166. begin
  1167. Result.JsonValue := TJSONString.Create(aValue.ToString);
  1168. end;
  1169. tkRecord :
  1170. begin
  1171. rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
  1172. try
  1173. json := TJSONObject.Create;
  1174. for rField in rRec.GetFields do
  1175. begin
  1176. json.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
  1177. end;
  1178. Result.JsonValue := json;
  1179. finally
  1180. ctx.Free;
  1181. end;
  1182. end;
  1183. tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
  1184. begin
  1185. //skip these properties
  1186. //FreeAndNil(Result);
  1187. end
  1188. else
  1189. begin
  1190. raise EJsonSerializeError.CreateFmt(cNotSupportedDataType,[aName,GetTypeName(aValue.TypeInfo)]);
  1191. end;
  1192. end;
  1193. if Result.JsonValue = nil then Result.JsonValue := TJSONNull.Create;
  1194. except
  1195. on E : Exception do
  1196. begin
  1197. Result.Free;
  1198. raise EJsonSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
  1199. end;
  1200. end;
  1201. end;
  1202. {$ELSE}
  1203. function TRTTIJson.GetPropType(aPropInfo: PPropInfo): PTypeInfo;
  1204. begin
  1205. Result := aPropInfo^.PropType;
  1206. end;
  1207. function TRTTIJson.FloatProperty(aObject : TObject; aPropInfo: PPropInfo): string;
  1208. const
  1209. Precisions: array[TFloatType] of Integer = (7, 15, 18, 18, 19);
  1210. var
  1211. fsettings : TFormatSettings;
  1212. begin
  1213. fsettings := FormatSettings;
  1214. Result := StringReplace(FloatToStrF(GetFloatProp(aObject, aPropInfo), ffGeneral,
  1215. Precisions[GetTypeData(GetPropType(aPropInfo))^.FloatType],0),
  1216. '.',fsettings.DecimalSeparator,[rfReplaceAll]);
  1217. end;
  1218. function TRTTIJson.Serialize(const aName : string; aValue : TValue) : TJSONPair;
  1219. begin
  1220. Result := TJSONPair.Create(aName,nil);
  1221. //Result.JsonString := TJSONString(aName);
  1222. try
  1223. case avalue.Kind of
  1224. tkClass :
  1225. begin
  1226. Result.JsonValue := TJSONValue(Serialize(aValue.AsObject));
  1227. end;
  1228. tkString, tkLString, tkWString, tkUString :
  1229. begin
  1230. Result.JsonValue := TJSONString.Create(aValue.AsString);
  1231. end;
  1232. tkChar, tkWChar :
  1233. begin
  1234. Result.JsonValue := TJSONString.Create(aValue.AsString);
  1235. end;
  1236. tkInteger :
  1237. begin
  1238. Result.JsonValue := TJSONNumber.Create(aValue.AsInteger);
  1239. end;
  1240. tkInt64 :
  1241. begin
  1242. Result.JsonValue := TJSONNumber.Create(aValue.AsInt64);
  1243. end;
  1244. tkFloat :
  1245. begin
  1246. if aValue.TypeInfo = TypeInfo(TDateTime) then
  1247. begin
  1248. Result.JsonValue := TJSONString.Create(DateTimeToJsonDate(aValue.AsExtended));
  1249. end
  1250. else if aValue.TypeInfo = TypeInfo(TDate) then
  1251. begin
  1252. Result.JsonValue := TJSONString.Create(DateToStr(aValue.AsExtended));
  1253. end
  1254. else if aValue.TypeInfo = TypeInfo(TTime) then
  1255. begin
  1256. Result.JsonValue := TJSONString.Create(TimeToStr(aValue.AsExtended));
  1257. end
  1258. else
  1259. begin
  1260. Result.JsonValue := TJSONNumber.Create(aValue.AsExtended);
  1261. end;
  1262. end;
  1263. tkEnumeration :
  1264. begin
  1265. if (aValue.TypeInfo = System.TypeInfo(Boolean)) then
  1266. begin
  1267. Result.JsonValue := TJSONBool.Create(aValue.AsBoolean);
  1268. end
  1269. else
  1270. begin
  1271. //Result.JsonValue := TJSONString.Create(GetEnumName(aValue.TypeInfo,aValue.AsOrdinal));
  1272. if fUseEnumNames then Result.JsonValue := TJSONString.Create(aValue.ToString)
  1273. else Result.JsonValue := TJSONNumber.Create(GetEnumValue(aValue.TypeInfo,aValue.ToString));
  1274. end;
  1275. end;
  1276. tkSet :
  1277. begin
  1278. Result.JsonValue := TJSONString.Create(aValue.ToString);
  1279. end;
  1280. else
  1281. begin
  1282. //raise EJsonDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
  1283. end;
  1284. end;
  1285. if Result.JsonValue = nil then Result.JsonValue := TJSONNull.Create;
  1286. except
  1287. Result.Free;
  1288. end;
  1289. end;
  1290. function TRTTIJson.Serialize(aObject : TObject; aType : TTypeKind; const aPropertyName : string) : TJSONPair;
  1291. var
  1292. propinfo : PPropInfo;
  1293. jArray : TJsonArray;
  1294. jPair : TJsonPair;
  1295. jValue : TJsonValue;
  1296. i : Integer;
  1297. pArr : Pointer;
  1298. rValue : TValue;
  1299. rItemValue : TValue;
  1300. len : Integer;
  1301. begin
  1302. try
  1303. Result := TJSONPair.Create(aPropertyName,nil);
  1304. propinfo := GetPropInfo(aObject,aPropertyName);
  1305. //case propinfo.PropType.Kind of
  1306. case aType of
  1307. tkDynArray :
  1308. begin
  1309. len := 0;
  1310. jArray := TJSONArray.Create;
  1311. try
  1312. pArr := GetDynArrayProp(aObject,aPropertyName);
  1313. TValue.Make(@pArr,propinfo.PropType, rValue);
  1314. if rValue.IsArray then
  1315. begin
  1316. len := rValue.GetArrayLength;
  1317. for i := 0 to len - 1 do
  1318. begin
  1319. rItemValue := rValue.GetArrayElement(i);
  1320. jPair := Serialize(aPropertyName,rItemValue);
  1321. try
  1322. //jValue := TJsonValue(jPair.JsonValue.Clone);
  1323. jValue := jPair.JsonValue;
  1324. jArray.Add(jValue);
  1325. //jPair.JsonValue.Owned := False;
  1326. finally
  1327. jPair.Free;
  1328. //jValue.Owned := True;
  1329. end;
  1330. end;
  1331. end;
  1332. Result.JsonValue := jArray;
  1333. finally
  1334. //DynArrayClear(pArr,propinfo.PropType);
  1335. pArr := nil;
  1336. end;
  1337. end;
  1338. tkClass :
  1339. begin
  1340. Result.JsonValue := TJSONValue(Serialize(GetObjectProp(aObject,aPropertyName)));
  1341. end;
  1342. tkString, tkLString, tkWString, tkUString, tkAString :
  1343. begin
  1344. Result.JsonValue := TJSONString.Create(GetStrProp(aObject,aPropertyName));
  1345. end;
  1346. tkChar, tkWChar :
  1347. begin
  1348. Result.JsonValue := TJSONString.Create(Char(GetOrdProp(aObject,aPropertyName)));
  1349. end;
  1350. tkInteger :
  1351. begin
  1352. Result.JsonValue := TJSONNumber.Create(GetOrdProp(aObject,aPropertyName));
  1353. end;
  1354. tkInt64 :
  1355. begin
  1356. Result.JsonValue := TJSONNumber.Create(GetOrdProp(aObject,aPropertyName));
  1357. end;
  1358. tkFloat :
  1359. begin
  1360. if propinfo.PropType = TypeInfo(TDateTime) then
  1361. begin
  1362. Result.JsonValue := TJSONString.Create(DateTimeToJsonDate(GetFloatProp(aObject,aPropertyName)));
  1363. end
  1364. else if propinfo.PropType = TypeInfo(TDate) then
  1365. begin
  1366. Result.JsonValue := TJSONString.Create(DateToStr(GetFloatProp(aObject,aPropertyName)));
  1367. end
  1368. else if propinfo.PropType = TypeInfo(TTime) then
  1369. begin
  1370. Result.JsonValue := TJSONString.Create(TimeToStr(GetFloatProp(aObject,aPropertyName)));
  1371. end
  1372. else
  1373. begin
  1374. //Result.JsonValue := TJsonFloatNumber.Create(GetFloatProp(aObject,aPropertyName));
  1375. Result.JsonValue := TJsonFloatNumber.Create(StrToFloat(FloatProperty(aObject,propinfo)));
  1376. end;
  1377. end;
  1378. tkEnumeration,tkBool :
  1379. begin
  1380. if (propinfo.PropType = System.TypeInfo(Boolean)) then
  1381. begin
  1382. Result.JsonValue := TJSONBool.Create(Boolean(GetOrdProp(aObject,aPropertyName)));
  1383. end
  1384. else
  1385. begin
  1386. if fUseEnumNames then Result.JsonValue := TJSONString.Create(GetEnumName(propinfo.PropType,GetOrdProp(aObject,aPropertyName)))
  1387. else Result.JsonValue := TJSONNumber.Create(GetOrdProp(aObject,aPropertyName));
  1388. //Result.JsonValue := TJSONString.Create(aValue.ToString);
  1389. end;
  1390. end;
  1391. tkSet :
  1392. begin
  1393. Result.JsonValue := TJSONString.Create(GetSetProp(aObject,aPropertyName));
  1394. end;
  1395. {$IFNDEF FPC}
  1396. tkRecord :
  1397. begin
  1398. rRec := ctx.GetType(aValue.TypeInfo).AsRecord;
  1399. try
  1400. json := TJSONObject.Create;
  1401. for rField in rRec.GetFields do
  1402. begin
  1403. json.AddPair(Serialize(rField.name,rField.GetValue(aValue.GetReferenceToRawData)));
  1404. end;
  1405. Result.JsonValue := json;
  1406. finally
  1407. ctx.Free;
  1408. end;
  1409. end;
  1410. {$ENDIF}
  1411. tkMethod, tkPointer, tkClassRef ,tkInterface, tkProcedure :
  1412. begin
  1413. //skip these properties
  1414. //FreeAndNil(Result);
  1415. end
  1416. else
  1417. begin
  1418. //raise EJsonDeserializeError.CreateFmt('Not supported type "%s":%d',[aName,Integer(aValue.Kind)]);
  1419. end;
  1420. end;
  1421. if Result.JsonValue = nil then Result.JsonValue := TJSONNull.Create;
  1422. except
  1423. on E : Exception do
  1424. begin
  1425. Result.Free;
  1426. {$IFNDEF FPC}
  1427. raise EJsonSerializeError.CreateFmt('Serialize error class "%s.%s" : %s',[aName,aValue.ToString,e.Message]);
  1428. {$ENDIF}
  1429. end;
  1430. end;
  1431. end;
  1432. {$ENDIF}
  1433. { TJsonSerializer}
  1434. constructor TJsonSerializer.Create(aSerializeLevel: TSerializeLevel; aUseEnumNames : Boolean = True);
  1435. begin
  1436. {$IFDEF FPC}
  1437. if aSerializeLevel = TSerializeLevel.slPublicProperty then raise EJsonSerializeError.Create('FreePascal RTTI only supports published properties');
  1438. {$ENDIF}
  1439. fSerializeLevel := aSerializeLevel;
  1440. fUseEnumNames := aUseEnumNames;
  1441. fUseJsonCaseSense := False;
  1442. fRTTIJson := TRTTIJson.Create(aSerializeLevel,aUseEnumNames);
  1443. fRTTIJson.UseJsonCaseSense := fUseJsonCaseSense;
  1444. end;
  1445. function TJsonSerializer.JsonToObject(aType: TClass; const aJson: string): TObject;
  1446. var
  1447. json: TJSONObject;
  1448. begin
  1449. json := TJSONObject.ParseJSONValue(aJson,True) as TJSONObject;
  1450. try
  1451. Result := fRTTIJson.DeserializeClass(aType,json);
  1452. finally
  1453. json.Free;
  1454. end;
  1455. end;
  1456. destructor TJsonSerializer.Destroy;
  1457. begin
  1458. fRTTIJson.Free;
  1459. inherited;
  1460. end;
  1461. function TJsonSerializer.JsonToObject(aObject: TObject; const aJson: string): TObject;
  1462. var
  1463. json: TJSONObject;
  1464. begin
  1465. json := TJsonObject(TJSONObject.ParseJSONValue(aJson,True));
  1466. try
  1467. Result := fRTTIJson.DeserializeObject(aObject,json);
  1468. finally
  1469. json.Free;
  1470. end;
  1471. end;
  1472. function TJsonSerializer.ObjectToJson(aObject : TObject; aIndent : Boolean = False): string;
  1473. var
  1474. json: TJSONObject;
  1475. begin
  1476. json := fRTTIJson.Serialize(aObject);
  1477. try
  1478. if aIndent then Result := TJsonUtils.JsonFormat(json.ToJSON)
  1479. else Result := json.ToJSON;
  1480. finally
  1481. json.Free;
  1482. end;
  1483. end;
  1484. function TJsonSerializer.ObjectToJsonString(aObject : TObject; aIndent : Boolean = False): string;
  1485. var
  1486. json: TJSONObject;
  1487. begin
  1488. json := fRTTIJson.Serialize(aObject);
  1489. try
  1490. if aIndent then Result := TJsonUtils.JsonFormat(json.ToString)
  1491. else Result := json.ToString;
  1492. finally
  1493. json.Free;
  1494. end;
  1495. end;
  1496. procedure TJsonSerializer.SetUseEnumNames(const Value: Boolean);
  1497. begin
  1498. fUseEnumNames := Value;
  1499. if Assigned(fRTTIJson) then fRTTIJson.UseEnumNames := Value;
  1500. end;
  1501. procedure TJsonSerializer.SetUseJsonCaseSense(const Value: Boolean);
  1502. begin
  1503. fUseJsonCaseSense := Value;
  1504. if Assigned(fRTTIJson) then fRTTIJson.UseJsonCaseSense := Value;
  1505. end;
  1506. {$IFNDEF FPC}
  1507. { TCommentProperty }
  1508. constructor TCommentProperty.Create(const aComment: string);
  1509. begin
  1510. fComment := aComment;
  1511. end;
  1512. { TCustomNameProperty }
  1513. constructor TCustomNameProperty.Create(const aName: string);
  1514. begin
  1515. fName := aName;
  1516. end;
  1517. {$ENDIF}
  1518. end.