Quick.Json.Serializer.pas 64 KB

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