KodeZwerg 54 Posted August 3, 2023 I have a problem with Delphi Alexandria and it's JSON methods, maybe I just do it wrong and would like to get help. Here is my demo project that show the problem. program Project12; {$APPTYPE CONSOLE} {$R *.res} uses Winapi.Windows, System.Classes, System.SysUtils, System.IOUtils, System.JSON; type TMyJsonRec = packed record MyInteger: Integer; MyInt64: Int64; MyUInt64: UInt64; MyDWORD: DWORD; MyDouble: Double; MyBoolean: Boolean; MyString: string; end; procedure SaveJsonToFile(const AJsonObject: TJSONObject; const AFileName: string); var JsonText: string; StreamWriter: TStreamWriter; begin JsonText := AJsonObject.ToString; // is this the problematic part? StreamWriter := TStreamWriter.Create(AFileName, False, TEncoding.UTF8); try StreamWriter.Write(JsonText); finally StreamWriter.Free; end; end; procedure SaveRecordToJson(const ARecord: TMyJsonRec; const AFileName: string); var JsonObject: TJSONObject; begin JsonObject := TJSONObject.Create; try JsonObject.AddPair('MyInteger', TJSONNumber.Create(ARecord.MyInteger)); JsonObject.AddPair('MyInt64', TJSONNumber.Create(ARecord.MyInt64)); JsonObject.AddPair('MyUInt64', TJSONNumber.Create(ARecord.MyUInt64)); // this does not work as I would have thought it does, when it exceed Int64 range it break JsonObject.AddPair('MyDWORD', TJSONNumber.Create(ARecord.MyDWORD)); JsonObject.AddPair('MyDouble', TJSONNumber.Create(ARecord.MyDouble)); JsonObject.AddPair('MyBoolean', TJSONBool.Create(ARecord.MyBoolean)); JsonObject.AddPair('MyString', ARecord.MyString); SaveJsonToFile(JSonObject, AFileName); finally JsonObject.Free; end; end; function LoadRecordFromJson(const AFileName: string): TMyJsonRec; var JsonObject: TJSONObject; begin JsonObject := TJSONObject.ParseJSONValue(TFile.ReadAllText(AFileName)) as TJSONObject; try Result.MyInteger := JsonObject.GetValue('MyInteger').AsType<Integer>; Result.MyInt64 := JsonObject.GetValue('MyInt64').AsType<Int64>; Result.MyUInt64 := JsonObject.GetValue('MyUInt64').AsType<UInt64>; // this does not work as I would have thought it does, when it exceed Int64 range it break Result.MyDWORD := JsonObject.GetValue('MyDWORD').AsType<DWORD>; Result.MyDouble := JsonObject.GetValue('MyDouble').AsType<Double>; Result.MyBoolean := JsonObject.GetValue('MyBoolean').AsType<Boolean>; Result.MyString := JsonObject.GetValue('MyString').Value; finally JsonObject.Free; end; end; var MyRecord1, MyRecord2: TMyJsonRec; begin // Initialize the record MyRecord1.MyInteger := High(Integer); MyRecord1.MyInt64 := High(Int64); MyRecord1.MyUInt64 := High(UInt64); MyRecord1.MyDWORD := High(DWORD); MyRecord1.MyDouble := 123.456; MyRecord1.MyBoolean := True; MyRecord1.MyString := 'Hello, World!'; Writeln('Original record:'); Writeln('MyInteger: ', MyRecord1.MyInteger); Writeln('MyInt64: ', MyRecord1.MyInt64); Writeln('MyUInt64: ', MyRecord1.MyUInt64); Writeln('MyDWORD: ', MyRecord1.MyDWORD); Writeln('MyDouble: ', MyRecord1.MyDouble); Writeln('MyBoolean: ', MyRecord1.MyBoolean); Writeln('MyString: ', MyRecord1.MyString); SaveRecordToJson(MyRecord1, '.\test.json'); MyRecord2 := LoadRecordFromJson('.\test.json'); // Output the loaded record Writeln('Loaded record:'); Writeln('MyInteger: ', MyRecord2.MyInteger); Writeln('MyInt64: ', MyRecord2.MyInt64); Writeln('MyUInt64: ', MyRecord2.MyUInt64); Writeln('MyDWORD: ', MyRecord2.MyDWORD); Writeln('MyDouble: ', MyRecord2.MyDouble); Writeln('MyBoolean: ', MyRecord2.MyBoolean); Writeln('MyString: ', MyRecord2.MyString); ReadLn; end. I am unsure if it is the saving part or the reading part. Share this post Link to post
Attila Kovacs 629 Posted August 3, 2023 Be careful with those numbers, they can bite. https://lwn.net/Articles/730671/ Share this post Link to post
KodeZwerg 54 Posted August 3, 2023 Does that mean I can not use UInt64 type in combination with JSON via Delphi's built-in JSON units? Share this post Link to post
Uwe Raabe 2057 Posted August 3, 2023 Probably not. Although it accepts UINT64 at creation, there is no support for retrieving it. I suggest to file a QP report. Share this post Link to post
Attila Kovacs 629 Posted August 3, 2023 55 minutes ago, KodeZwerg said: Does that mean I can not use UInt64 type in combination with JSON via Delphi's built-in JSON units? That means those numbers are implicitly converted to anything by every interpreter. If necessary, you may consider using strings instead. Share this post Link to post
Uwe Raabe 2057 Posted August 3, 2023 I have to revert my statement: Currently not even creation of a UINT64 is supported. Nevertheless, the values are always stored as string, so no restrictions apply here. It is the responsibility of the developer to do the conversion needed. For completeness I suggest to create a QP request. Internally it needs just some extension to the case statement in TJSONString.AsTValue. Share this post Link to post
KodeZwerg 54 Posted August 4, 2023 Thank you @Attila Kovacs, I will try it with string conversation! Thank you @Uwe Raabefor confirming and suggestion me to create RSP-42079. I hope I did fill out the form there correct. Share this post Link to post
Uwe Raabe 2057 Posted August 4, 2023 This can be easily solved by converting to string before calling the constructor: JSonObject.AddPair('Test', TJSONNumber.Create(High(UInt64).ToString)); // add System.SysUtils to uses clause If the UINT64 value is already correct in the JSON string it is properly converted to an UNIT64 later. Share this post Link to post