Quick.Json.Serializer.pas 60 KB

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