Quick.Options.Serializer.Json.pas 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. { ***************************************************************************
  2. Copyright (c) 2015-2021 Kike Pérez
  3. Unit : Quick.Options.Serializer.Json
  4. Description : Configuration groups Json Serializer
  5. Author : Kike Pérez
  6. Version : 1.0
  7. Created : 18/10/2019
  8. Modified : 15/12/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.Options.Serializer.Json;
  22. {$i QuickLib.inc}
  23. interface
  24. uses
  25. System.SysUtils,
  26. System.IOUtils,
  27. System.Generics.Collections,
  28. System.Json,
  29. Quick.Commons,
  30. Quick.JSON.Utils,
  31. Quick.Json.Serializer,
  32. Quick.Options;
  33. type
  34. TJsonOptionsSerializer = class(TOptionsFileSerializer)
  35. private
  36. fSerializer : TRTTIJson;
  37. function ParseFile(out aJsonObj : TJsonObject) : Boolean;
  38. public
  39. constructor Create(const aFilename : string);
  40. destructor Destroy; override;
  41. function Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean; override;
  42. function LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean; override;
  43. procedure Save(aSections : TSectionList); override;
  44. function GetFileSectionNames(out oSections : TArray<string>) : Boolean; override;
  45. function ConfigExists : Boolean; override;
  46. end;
  47. implementation
  48. { TJsonOptionsSerializer }
  49. function TJsonOptionsSerializer.ConfigExists: Boolean;
  50. begin
  51. Result := FileExists(Filename);
  52. end;
  53. constructor TJsonOptionsSerializer.Create(const aFilename : string);
  54. begin
  55. Filename := aFilename;
  56. fSerializer := TRTTIJson.Create(TSerializeLevel.slPublishedProperty,True);
  57. end;
  58. destructor TJsonOptionsSerializer.Destroy;
  59. begin
  60. fSerializer.Free;
  61. inherited;
  62. end;
  63. function TJsonOptionsSerializer.GetFileSectionNames(out oSections: TArray<string>): Boolean;
  64. var
  65. json : TJsonObject;
  66. i : Integer;
  67. begin
  68. Result := False;
  69. json := nil;
  70. if ParseFile(json) then
  71. begin
  72. try
  73. for i := 0 to json.Count - 1 do
  74. begin
  75. oSections := oSections + [json.Pairs[i].JsonString.Value];
  76. end;
  77. Result := True;
  78. finally
  79. json.Free;
  80. end;
  81. end;
  82. end;
  83. function TJsonOptionsSerializer.ParseFile(out aJsonObj : TJsonObject) : Boolean;
  84. var
  85. fileoptions : string;
  86. begin
  87. aJsonObj := nil;
  88. if FileExists(Filename) then
  89. begin
  90. {$IFDEF DELPHIRX102_UP}
  91. fileoptions := TFile.ReadAllText(Filename,TEncoding.UTF8);
  92. {$ELSE}
  93. fileoptions := TFile.ReadAllText(fFilename);
  94. {$ENDIF}
  95. aJsonObj := TJsonObject.ParseJSONValue(fileoptions) as TJsonObject;
  96. if aJsonObj = nil then raise EOptionLoadError.CreateFmt('Config file "%s" is damaged or not well-formed Json format!',[ExtractFileName(Filename)]);
  97. end;
  98. Result := aJsonObj <> nil;
  99. end;
  100. function TJsonOptionsSerializer.Load(aSections : TSectionList; aFailOnSectionNotExists : Boolean) : Boolean;
  101. var
  102. option : TOptions;
  103. json : TJsonObject;
  104. jpair : TJSONPair;
  105. found : Integer;
  106. begin
  107. Result := False;
  108. if ParseFile(json) then
  109. begin
  110. found := 0;
  111. try
  112. for option in aSections do
  113. begin
  114. jpair := fSerializer.GetJsonPairByName(json,option.Name);
  115. if jpair = nil then
  116. begin
  117. if aFailOnSectionNotExists then raise Exception.CreateFmt('Config section "%s" not found',[option.Name])
  118. else
  119. begin
  120. //count as found if hidden
  121. if option.HideOptions then Inc(found);
  122. Continue;
  123. end;
  124. end;
  125. if jpair.JsonValue <> nil then
  126. begin
  127. //deserialize option
  128. fSerializer.DeserializeObject(option,jpair.JsonValue as TJSONObject);
  129. //validate loaded configuration
  130. option.ValidateOptions;
  131. Inc(found);
  132. end;
  133. end;
  134. finally
  135. json.Free;
  136. end;
  137. //returns true if all sections located into file
  138. Result := found = aSections.Count;
  139. end;
  140. end;
  141. function TJsonOptionsSerializer.LoadSection(aSections : TSectionList; aOptions: TOptions) : Boolean;
  142. var
  143. json : TJsonObject;
  144. jpair : TJSONPair;
  145. begin
  146. Result := False;
  147. //read option file
  148. if ParseFile(json) then
  149. begin
  150. try
  151. jpair := fSerializer.GetJsonPairByName(json,aOptions.Name);
  152. if (jpair <> nil) and (jpair.JsonValue <> nil) then
  153. begin
  154. //deserialize option
  155. fSerializer.DeserializeObject(aOptions,jpair.JsonValue as TJSONObject);
  156. //validate loaded configuration
  157. aOptions.ValidateOptions;
  158. Result := True;
  159. end;
  160. finally
  161. json.Free;
  162. end;
  163. end;
  164. end;
  165. procedure TJsonOptionsSerializer.Save(aSections : TSectionList);
  166. var
  167. option : TOptions;
  168. fileoptions : string;
  169. json : TJSONObject;
  170. jpair : TJSONPair;
  171. begin
  172. json := TJSONObject.Create;
  173. try
  174. for option in aSections do
  175. begin
  176. if not option.HideOptions then
  177. begin
  178. //validate configuration before save
  179. option.ValidateOptions;
  180. //serialize option
  181. jpair := TJSONPair.Create(option.Name,fSerializer.SerializeObject(option));
  182. json.AddPair(jpair);
  183. end;
  184. end;
  185. fileoptions := TJsonUtils.JsonFormat(json.ToJSON);
  186. if not fileoptions.IsEmpty then TFile.WriteAllText(Filename,fileoptions);
  187. finally
  188. json.Free;
  189. end;
  190. end;
  191. end.