#1 2020-03-05 09:22:11

ertank
Member
Registered: 2016-03-16
Posts: 163

Json Array de-serialization problem

Hello,

I am using Delphi 10.3.3, Synopse is updated from github. I double check that I am using latest version of SynCommons.pas

I have a simple json string (json array) that I fail to find why I cannot de-serialize. I simply fail to find a reason.

I do appreciate any help.

Record definition:

  TStVATDetail = packed record
    u32VAT: Integer;
    u32Amount: Integer;
    u16VATPercentage: UInt16;
  end;
  TStVATDetails = Array of TStVATDetail;

Json array that I cannot de-serialize:

[{"u32VAT":15,"u32Amount":100,"u16VATPercentage":1800},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":800},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":100},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":2400},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0}]

My code for de-serialization:

const
  Json = '[{"u32VAT":15,"u32Amount":100,"u16VATPercentage":1800},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":800},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":100},' +
         '{"u32VAT":0,"u32Amount":0,"u16VATPercentage":2400},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0}]';

procedure TForm3.Button1Click(Sender: TObject);
var
  Taxes: TStVATDetails;
begin
  if not SynCommons.DynArrayLoadJSON(Taxes, RawUTF8(Json), TypeInfo(TStVATDetails)) then
  begin
    ShowMessage('Cannot deserialize Json!');
  end
  else
  begin
    ShowMessage('Json deserialization OK');
  end;
end;

Offline

#2 2020-03-05 09:36:09

Chaa
Member
Registered: 2011-03-26
Posts: 244

Re: Json Array de-serialization problem

DynArrayLoadJSON modified JSON-buffer in-place when parsing.
You pass const string and function fails. Try:

var
  Taxes: TStVATDetails;
  S: RawUTF8;
begin
  S:= Json;
  if DynArrayLoadJSON(Taxes, UniqueRawUTF8(S), TypeInfo(TStVATDetails)) then...
end;

Offline

#3 2020-03-05 10:08:26

ertank
Member
Registered: 2016-03-16
Posts: 163

Re: Json Array de-serialization problem

There is an overloaded version of DynArrayLoadJSON in SynCommons.pas. My code supposed to use it

function DynArrayLoadJSON(var Value; const JSON: RawUTF8; TypeInfo: pointer): boolean;
var tmp: TSynTempBuffer;
begin
  tmp.Init(JSON); // make private copy before in-place decoding
  try
    result := DynArrayLoadJSON(Value,tmp.buf,TypeInfo)<>nil;
  finally
    tmp.Done;
  end;
end;

Offline

#4 2020-03-05 10:28:26

Chaa
Member
Registered: 2011-03-26
Posts: 244

Re: Json Array de-serialization problem

Delphi does not create RTTI information for records without managed fields (like String, Variant, Array, Interface).

So there are 3 option:
1. Add managed field
2. Use text-based definition https://synopse.info/files/html/Synopse … #TITLE_242
3. Use custom serialization

Offline

#5 2020-03-05 11:33:53

ertank
Member
Registered: 2016-03-16
Posts: 163

Re: Json Array de-serialization problem

I do not know details of RTTI. However, below code works for the first one and not for the second one. I do get "json2 OK" displayed on the screen. That is without using any of suggested 3 options above.

const
  Json = '[{"u32VAT":15,"u32Amount":100,"u16VATPercentage":1800},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":800},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":100},' +
         '{"u32VAT":0,"u32Amount":0,"u16VATPercentage":2400},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0},{"u32VAT":0,"u32Amount":0,"u16VATPercentage":0}]';
  Json2 = '{"u32VAT":15,"u32Amount":100,"u16VATPercentage":1800}';

procedure TForm3.Button1Click(Sender: TObject);
var
  Taxes: TStVATDetails;
  Tax: TStVATDetail;
begin
  if SynCommons.RecordLoadJSON(Tax, RawUTF8(Json2), TypeInfo(TStVATDetail)) then
    ShowMessage('json2 OK')
  else
    ShowMessage('json2 failed');

  if not SynCommons.DynArrayLoadJSON(Taxes, RawUTF8(Json), TypeInfo(TStVATDetails)) then
  begin
    ShowMessage('Cannot deserialize Json!');
  end
  else
  begin
    ShowMessage('Json deserialization OK');
  end;
end;

Offline

#6 2020-03-05 11:51:56

Chaa
Member
Registered: 2011-03-26
Posts: 244

Re: Json Array de-serialization problem

Type TStVATDetail has type information, but TStVATDetails does not, because compiler not needed for it - no managed fields in record, so compiler might simply free memory used for array.
Try change your record:

TStVATDetail = packed record
    u32VAT: Integer;
    u32Amount: Integer;
    u16VATPercentage: UInt16;
    s: String;
  end;

And you will see that code now works.

Offline

#7 2020-03-05 14:45:36

ertank
Member
Registered: 2016-03-16
Posts: 163

Re: Json Array de-serialization problem

That did indeed work.

Offline

Board footer

Powered by FluxBB