Quick.Json.Serializer.pas 51 KB

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