Quick.Json.Serializer.pas 47 KB

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