English
Recently, EMBT published an interesting article in their official news: "This Is How To Store Cross Platform App Settings In JSON" by the Softacom Information team. This emerging team collects and publishes articles from Delphi enthusiasts worldwide, so it's unclear who the original author is.
The article discusses that in addition to XML (Extensible Markup Language) and
INI (Initial) formats, modern cross-platform applications often use JSON for
configuration files, with Visual Studio Code as a classic example.
Visual Studio Code Workspace Settings File |
The article pointed out that Delphi provides two JSON libraries: JSON Objects Framework and Readers and Writers JSON Framework. The author also mentioned the most widely used alternative open-source option, X-SuperObject, provided by Turkish engineer Onur YILDIZ. It's interesting to note that the JSON Objects Framework provides JSON Marshaling/Un-Marshaling, so what makes it different from X-SuperObject?
Delphi developers are spoiled for choice when it comes to using JSON. Realy?
The author complains that Delphi engineers have been spoiled by the official JSON frameworks. Is that true?
The article points out that Delphi provides two JSON libraries: JSON Objects Framework and Readers and Writers JSON Framework. As an alternative, the author suggests using the widely popular open-source variant X-SuperObject by Turkish engineer Onur YILDIZ. Curiously, JSON Objects Framework provides JSON Marshaling/Un-Marshaling, so how does it differ from X-SuperObject?
Example using JSON Objects Framework
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | TContact = class(TObject) public Name: string; Age: Integer; function ToString: string; override; end; procedure TForm1.JSONMarshalClick(Sender: TObject); var LContact: TContact; oMarshaller: TJSONMarshal; crtVal: TJSONValue; begin LContact := TContact.Create; //our custom class LContact.Name:='Hello Eden'; LContact.Age := 20; //fill with some data oMarshaller := TJSONMarshal.Create(TJSONConverter.Create); //our engine crtVal := oMarshaller.Marshal(LContact); //serialize to JSON try Memo1.Text := crtVal.ToString; //display finally //cleanup FreeAndNil(LContact); FreeAndNil(oMarshaller); crtVal.Free; end; end; |
Example execution result using JSON Objects Framework
1 2 3 4 5 6 7 8 | { "type": "Unit2.TContact", "id": 1, "fields": { "Name": "Hello Eden", "Age": 20 } } |
Example execution result using JSON Objects Framework
The JSON format produced by TObject using the JSON Objects Framework (JOF) is not as intuitive as the one produced by X-SuperObject. Users might need some time to learn the JOF format to manage their configurations.
This has to do with the original purpose of JOF. Around 2009, Delphi 2009 made a transition in DataSnap Framework from XML RPC to JSON RPC. As mentioned earlier, JOF was initially created to serve DataSnap, among other things, such as handling Delphi TObject's strong typing. Therefore, the format produced by JOF is not a weakly-typed compatible JSON format.
Why doesn't JOF produce widely accepted JSON formats?
So, the author's claim that Delphi engineers are spoiled by the two built-in JSON frameworks is not baseless. After getting used to Delphi's native tools, it may be difficult to accept content that deviates from the "Delphi standard."
Creating your desired format using JOF
Knowing that the built-in JOF won't produce a generic JSON format, you can still create your own. Have you heard of TDBXJSONTools? It can be used to convert TDataSet to JSON, so let's add TObject-to-JSON functionality to it!
TDBXJSONToolsHelper adds ObjToJSON functionality |
The original example is excellent and deserves a 5-star rating. I modified the example into a VCL project and replaced X-SuperObject usage with JOF, such as in the configuration file loading section:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | procedure TMyProgSettings.LoadFromFile(AFileName: string = ''); var LJObj: TJSONObject; begin if AFileName = '' then AFileName := GetDefaultSettingsFilename(); if not FileExists(AFileName) then Exit; LJObj := TJSONObject.Create; try if LJObj.Parse(TFile.ReadAllBytes(AFileName), 0) > 0 then begin // Magic method from Eden's TDBXJSONToolsHelper unit TDBXJSONTools.JsonToObj(LJObj, Self); end; finally LJObj.Free; end; end; |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | procedure TMyProgSettings.SaveToFile(AFileName: string = ''); var Json: string; begin if AFileName = '' then AFileName := GetDefaultSettingsFilename(); // Magic method from Eden's TDBXJSONToolsHelper unit with TDBXJSONTools.ObjToJSON(Self) do begin Json := ToJson; TFile.WriteAllText(AFileName, Json, TEncoding.UTF8); Free; end; end; |
Conclusion
Being "spoiled" by JOF is, in my opinion, a blessing. JOF is a framework well worth learning, and X-SuperObject offers even more features for JSON writing. If you frequently need to write JSON objects, X-SuperObject will definitely win your heart. Additionally, I enjoyed the original author's example of a login process using a while loop to control the login window; it's a great concept to learn.
You can download the TDBXJSONToolsHelper and VCL example program from my Github website: https://github.com/Eden5Wu/HelperClass/tree/master/Demo-JSON/JsonMarshalling
In summary, both the JSON Objects Framework (JOF) and X-SuperObject have their own unique advantages when working with JSON in Delphi. Developers should choose between them based on their specific needs and preferences.
For developers familiar with the Delphi style, JOF provides a familiar environment for working with JSON. However, if you need more control over JSON object writing, then X-SuperObject may be a better choice.
In any case, exploring and learning about the different JSON frameworks available is essential. By understanding their strengths and weaknesses, you can make more informed decisions about which tools to use in your projects.
Remember, practice and experimentation are key to becoming proficient in any programming language or framework. Therefore, don't be afraid to try different approaches and learn from the examples and experiences of other developers in the Delphi community.
中文版:使用 Delphi 寫出現代化 JSON 格式的設定檔案
最近 EMBT 官方新聞出現我很感興趣的文章:This Is How To Store Cross Platform App Settings In JSON,是由 Softacom Information 團隊執筆,這是一個新興團隊,匯整來自全球各地 Delphi 愛好者的文章並發表,所以還不知道真實原作者是誰。
原文作者說明在跨平台應用程式在讀寫設定檔時,除了 XML (Extensible Markup Language) 和 INI (Initial) 外,還有一個現代化應用程式常使用的設定檔格式:JSON,例如 Visual Studio Code 就是一個經典的參考。
Visual Studio Code 工作區設定檔 |
Delphi developers are spoiled for choice when it comes to using JSON.
Realy?
原作控訴 Delphi 工程師已經被官方 JSON 框架寵壞了 (笑),是真的嗎?
文章中指出 Delphi 提供 JSON 兩個函式庫:JSON Objects Framework 和 Readers and Writers JSON Framework;而原作設計上使用最廣泛的替代開源變體 —— 土耳其工程師 Onur YILDIZ 提供的 X-SuperObject。好奇的是,JSON Objects Framework 有提供 JSON Marshaling / Un-Marshaling,這和 X-SuperObject 又有什麼不一樣嗎?
使用 JSON Objects Framework 編寫的範例
TContact = class(TObject)
public
Name: string;
Age: Integer;
function ToString: string; override;
end;
procedure TForm1.JSONMarshalClick(Sender: TObject);
var
LContact: TContact;
oMarshaller: TJSONMarshal;
crtVal: TJSONValue;
begin
LContact := TContact.Create; //our custom class
LContact.Name:='Hello Eden';
LContact.Age := 20; //fill with some data
oMarshaller := TJSONMarshal.Create(TJSONConverter.Create); //our engine
crtVal := oMarshaller.Marshal(LContact); //serialize to JSON
try
Memo1.Text := crtVal.ToString; //display
finally //cleanup
FreeAndNil(LContact);
FreeAndNil(oMarshaller);
crtVal.Free;
end;
end;
使用 JSON Objects Framework 編寫範例的執行結果
{
"type": "Unit2.TContact",
"id": 1,
"fields": {
"Name": "Hello Eden",
"Age": 20
}
}
比較 X-SuperObject 和 JSON Objects Framework
TObject 透過 JSON Objects Framework (JOF) 所產出的 JSON 格式並沒有像 X-SuperObject 產出的 JSON 格式來得直觀,若使用者要自行控制設定時恐怕還得花上一點時間學習 JOF 格式才行。
為什麼 JOF 不產出廣泛被接受的 JSON 格式?
這就要講到 JOF 是為什麼被做出來的,約 2009 年時,Delphi 2009 對 DataSnap
Framework 進行變革,由 XML RPC 轉向為 JSON RPC,由上可知,JOF 當初建構目標是為
DataSnap 而服務,當然這只是其中之一;例如還必須考慮到 Delphi TObject
強型別的對應等,所以 JOF 產出的格式自然不會是以弱型別相容的 JSON 格式。
所以原作指出 Delphi 工程師被內建的兩個 JSON 框架寵壞也不是沒有道理,因為習慣了
Delphi 原生工具後的確會很難接受非【Delphi 標準】的內容。
使用 JOF 拼出自己理想中的格式
已經知道內建的 JOF 不會產出通用 JSON
格式,不過轉個彎,自己來打造一個也是可以的,知道 TDBXJSONTools 嗎?TDataSet 轉
JSON 可以利用它來完成,就來為它加入 TObject 轉 JSON 功能!
TDBXJSONToolsHelper 添加 ObjToJSON 功能 |
原文的範例寫的真的棒,要給 5 星評價,我把範例改為 VCL 專案,並且把使用 X-SuperObject 的地方改為 JOF,例如載入設定檔案的地方:
procedure TMyProgSettings.LoadFromFile(AFileName: string = '');
var
LJObj: TJSONObject;
begin
if AFileName = '' then
AFileName := GetDefaultSettingsFilename();
if not FileExists(AFileName) then
Exit;
LJObj := TJSONObject.Create;
try
if LJObj.Parse(TFile.ReadAllBytes(AFileName), 0) > 0 then
begin
TDBXJSONTools.JsonToObj(LJObj, Self); // Magic method from Eden's TDBXJSONToolsHelper unit
end;
finally
LJObj.Free;
end;
end;
以及儲存設定檔案的地方:
procedure TMyProgSettings.SaveToFile(AFileName: string = '');
var
Json: string;
begin
if AFileName = '' then
AFileName := GetDefaultSettingsFilename();
// Magic method from Eden's TDBXJSONToolsHelper unit
with TDBXJSONTools.ObjToJSON(Self) do
begin
Json := ToJson;
TFile.WriteAllText(AFileName, Json, TEncoding.UTF8);
Free;
end;
end;
總結
能被 JOF 寵壞我個人是覺得是幸福的,JOF 是個非常值得一學的框架,而
X-SuperObject 多了更多對 JSON 寫入的功能,如果有經常對 JSON 物件寫入的需求,則
X-SuperObject 一定深得你心;另外也很喜歡原作範例中登入流程的程式內容,使用
while 迴圈控制登入視窗很有意思,要學起來。
你可以從我的 Github 網站下載 TDBXJSONToolsHelper 和 VCL 範例程式:https://github.com/Eden5Wu/HelperClass/tree/master/Demo-JSON/JsonMarshalling
See also
-
This Is How To Store Cross Platform App Settings In JSON
- 原作範例:https://github.com/SoftacomCompany/FMX.Settings-in-JSON
-
JOF 魔改範例:https://github.com/Eden5Wu/HelperClass/tree/master/Demo-JSON/JsonMarshalling
沒有留言:
張貼留言