Quick.Options.Serializer.Json.pas 5.8 KB

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