Jump to content
Sign in to follow this  
KodeZwerg

JSON and UInt64 problem

Recommended Posts

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

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

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
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

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

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

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×