You are not logged in.
I was trying to learn how to do it. That _JsonFast() is working just fine.
Thank you
Hello,
There is a situation where I need to conditionally send json value as null or as a record to a server. Since there is null involved, I declared my record using variant for that specific variable.
Problem is, I couldn't figure out a way to pass a record to variant. I tried to pass a string like below (actual record is more complex than the example).
type
TRec = packed record
int: Integer;
Val: Variant; // sometimes NULL sometimes a record
end;
TRec2 = packed record
Percentage: Double;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
LRec: TRec;
LRec2: TRec2;
LRecJson, LRec2Json: string;
begin
LRec2.Percentage := 1.5;
LRec2Json := string(mormot.core.json.RecordSaveJson(LRec2, TypeInfo(TRec2)));
LRec.int := 123;
LRec.Val := LRec2Json;
LRecJson := string(mormot.core.json.RecordSaveJson(LRec, TypeInfo(TRec)));
end;
Above code results below json string in LRecJson where Val contains a string value.
{"int":123,"Val":"{\"Percentage\":1.5}"}
What I am trying to achieve is to have Val contain a json object as below
{"int":123,"Val":{"Percentage":1.5}}
Is this possible using mORMot2 and records?
Thanks & Regards,
Ertan
Hello,
Below example fails using Delphi 12.
uses
mormot.core.json, mormot.core.base;
type TRec = packed record id: Integer; atime: TTime; end;
procedure TForm1.FormCreate(Sender: TObject);
const cData = '{id:123,atime:"15:30"}';
var LRec: TRec;
begin
if not mormot.core.json.RecordLoadJson(LRec, RawUtf8(cData), TypeInfo(TRec)) then
ShowMessage('not ok')
else
ShowMessage('deserialize completed');
end;
I know I can use TDateTime instead. Just asking for convenience. Is it possible to support TTime data type?
Thank you for your consideration.
Regards,
Ertan
You can overwrite the TDateTime format, but it would be global for the whole process.
I don't know how I can do that?
I am returning back to this specific date time format.
I see it can be de-serialized successfully into TDateTime if the field name is "timestamp" like below
type
TRec = packed record
timestamp: TDateTime;
end;
procedure TForm1.FormCreate(Sender: TObject);
const cData = '{"timestamp":"2024-08-02 21:02:13"}';
var LRec: TRec;
begin
mormot.core.json.RecordLoadJson(LRec, RawUtf8(cData), TypeInfo(TRec));
end;
I wonder if it is possible to widen this for TDateTime definitions using any name?
Thank you for your consideration.
Regards,
Ertan
That's working.
Thank you.
Hello,
I am using Delphi 12.2, mORMot from GitHub January 3, 2025 update.
Is it possible to have mORMot2 de-serialize to auto convert Unix Time (with/without milliseconds) Int64 values to TDateTime?
uses
System.DateUtils, mormot.core.json, mormot.core.base;
type
TTest = packed record
ADate: TDateTime;
end;
procedure TForm1.FormCreate(Sender: TObject);
const cTest = '{"adate":1736705403567}'; // with milliseconds
var LRec: TTest;
begin
mormot.core.json.RecordLoadJson(LRec, RawUtf8(cTest), TypeInfo(TTest));
ShowMessage(LRec.ADate.ToString());
end;
Above code cause an overflow (if turned on)
Thanks & Regards,
Ertan
Hello,
There are some web services insisting on "yyyy-mm-dd hh:nn:ss" format. Sometimes they even put only php format string "Y-m-d H:i:s" as their requirement.
Is it possible to have mORMot2 to serialize TDateTime values using a custom format?
Thanks & Regards,
Ertan
Tested and found no problems.
Thank you.
Hello,
I am using Delphi 12.2 and mORMot2 from September 24, 2024
As to my tests below code sample is not de-serialized
uses
mormot.core.base,
mormot.core.json;
type
TTest = packed record
adate: TDate;
end;
procedure TForm1.Button1Click(Sender: TObject);
const
cTest = '{"adate":"2025-01-01"}';
var
LData: TTest;
begin
mormot.core.json.RecordLoadJson(LData, RawUtf8(cTest), TypeInfo(TTest));
end;
The same json string can be de-serialized if I change TDate -> TDateTime in record.
I wonder if TDate datatype is not supported?
Thanks & Regards,
Ertan
I didn't know that mORMot2 has such ability and also that it is turned on by default.
I spotted that I missed several breaking format differences in the web service response.
Sorry about the noise.
Hello,
There is this java web service which is requesting and responding using the identical JSON format.
I have below record definition. That record is serialized and sent to the web service. There is no problem and it consumes it.
THuginTPSSaleOrderSaleItem = packed record
Quantity: Double;
Amount: Double;
PLUNo: Integer;
DepartmentId: Integer;
VatRate: Double;
end;
But, the web service is responding something like below
{
"Quantity": "2.00",
"Amount": "10.00",
"PLUNo": 1,
"DepartmentId": 1,
"VatRate": 0,
}
As you can see the web service respond has some numbers as double quoted (aka string).
I wonder if mORMot2 can de-serialize these numbers in double data type as defined in the record.
If it is possible, I do appreciate a small RecordLoadJson() example showing how I can build necessary parameters and pass them to the function.
Thanks & Regards,
Ertan
P.S. Both record and json examples are greatly minimized for keeping this post short.
I couldn't understand what I read from the document so I did some tests.
Base information
type
TTransaction = packed record
TxnId: Int64;
TxnTypeId: Int64;
end;
const
__TTransaction = 'TxnId Int64 TxnTypeId Int64';
var
Json: string = '{"test":"additional field","TxnId":1,"TxnTypeId":2}';
...
initialization
Rtti.RegisterFromText(TypeInfo(TTransaction), __TTransaction);
Tests I did are as follows:
// Test1 - no dialog displayed
if mormot.core.json.RecordLoadJson(Test, Json, TypeInfo(TTransaction), nil, False) then
ShowMessage('OK');
// Test2 - displays OK dialog
if mormot.core.json.RecordLoadJson(Test, Json, TypeInfo(TTransaction)) then
ShowMessage('OK');
Test2 is what I currently have in my unit using Synopse.pas.
It seems I don't need any additional code change as "Tolerant = true" as default and that is what I needed.
Thanks & Regards,
Ertan
Thank you. In file search returns so many results and repeated filenames that it seems I missed that note.
So, how can I tell mORMot2 to read ignore unknown fields?
Hello,
I have old code that I am converting to use mORMot2 and I have quite a lot code like below
const
__TTransaction = 'TxnId Int64 TxnTypeId Int64';
...
initialization
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TIngenicoResult), __TTransaction).Options := [soReadIgnoreUnknownFields];
I could not figure how I can put this so it will work the same as before.
Any help is appreciated.
Thanks & Regards,
Ertan
After calculations, I get 1.92KB per item average memory usage. It was around 5KB before.
That would suffice to continue with Win32 application.
Since increase is slow, I will figure an alternative solution in the future.
Thanks.
TDocVariant loads everything into memory, before you can iterate into its values.
Yes, I am going to make measurements. Getting ready for it.
I count on dvoInternNames, dvoInternValues parameters. I will see if it will be enough to keep memory very low as names identically repeat and there are values that repeat a lot.
1. I have changed the BOM support in mORMot 2, and now you can use Doc.InitJsonFromFile() with a BOM file.
Even if BOM is not a good idea for UTF-8...
InitJsonInPlace() is indeed low-level.
I do really appreciate that. Thank you. I also think BOM is not a good idea, but you eventually find it out of your control here and there.
2. I guess you can use dvoInternNames safely, but only dvoInternValues if most JSON values are likely to reappear in the input JSON.
Number values indeed repeat a lot like 1 and 2 only and that is for multiple different values.
3. If TDocVariant has troubles with the JSON, and if the structure is really simple, I would rather try to use a dynamic array of records for the storage.
It would be more efficient in terms of memory, and also performance. And using a dynamic array and records would be much easier to work with.
That file immediately goes into database for each item read. I will not keep its data in memory for any other purpose. So far TDocVariant seems to work just fine.
My mistake again, I assumed InitJSONInPlace returns Boolean, but it does not.
if Doc.InitJSONInPlace(Pointer(AnyTextFileToRawUtf8('users.json')), [dvoInternNames, dvoInternValues]) = nil then
begin
ShowMessage('Json file could not be loaded');
Exit();
end;
Now, I will go back to parsing and measure memory usage on my test data.
Thanks.
Try TDocVariantData.InitJSONInPlace(AnyTextFileToRawUtf8(FilePath));
I could not make compiler happy. InitJSONInPlace require PUTF8Char and AnyTextFileToRawUtf8 returns RawUTF8. However, compiler says
[dcc32 Error] Unit1.pas(44): E2010 Incompatible types: 'PUtf8Char' and 'UTF8String'
I tried several other conversion and explicitly using pointers. But, all of them lead to a compiler error.
Hello,
Problem was users.json file has BOM and so cannot be read by TDocVariantData.InitJsonFromFile() If I read it using TFile.ReadAllText('users.json', TEncoding.UTF8) it is just fine. However, reading file content in a text variable and then using it to Init TDocVariantData feels like additional memory usage especially on a considerably large file.
This file is received as ZIP format from a web service and I cannot change the way it is saved. Is there any option for TDocVariantData.InitJsonFromFile() that can possible make it work with files including BOM?
Thanks & Regards,
Ertan
I've never used TDocVariantData and I cannot find my way thru. Below is my current test code, but even if it is an json of array, code thinks otherwise and exits at Doc.IsArray check.
uses
mormot.core.variants, mormot.core.data;
procedure TForm1.Button1Click(Sender: TObject);
var
Doc: TDocVariantData;
I, TempInteger: Integer;
TempString: string;
begin
Doc.InitJsonFromFile('users.json', [dvoInternNames, dvoInternValues]);
if not Doc.IsArray then Exit();
repeat
TempString := Doc.GetValueOrEmpty('Identifier');
TempInteger := string('0' + Doc.GetValueOrEmpty('AppType')).ToInteger();
until (not Doc.Items.MoveNext);
end;
Can someone put me in right direction, please?
Thanks & Regards,
Ertan
Hello,
I have a well defined structured relatively big (195MiB) json file to parse. Using Delphi System.JSON unit it will likely crash on Win32 exe because average single structure needs around 5KB in memory. The file has more than 750.000 records and slowly increasing.
I could find about 5 threads in forum about "SAX". I could not find anything in documents. I believe (correct me if I am wrong) mORMot and very much likely mORMot2 has SAX json parsing.
I do appreciate an example on how to use SAX parsing, please.
BTW, I prefer mORMot2.
Thanks & Regards,
Ertan
A good reference for future.
Thank you.
This was what I have been looking for.
Both name and unit change and I failed to find it in mORMot2 sources.
Thank you.
Hi,
I have an old project that I need to make some changes and additons. I am using mORMot 1 in that project for json handling and now I want to switch using mORMot2.
But, I could not find any example project or some information (even on this forum) to adapt my code. It is more than possible I overlooked at it.
There is ThirdPartyDemos\martin-doyle\03-MethodBasedServices example project which has very basic json handling and that is all I could find.
I do not know if having just "mormot.core.json" is enough in uses list.
TTextWriter.RegisterCustomJSONSerializerFromText() is something that I use in old project and I could not see how to use/convert it to mORMot2.
I am also not quite sure how to serialize/de-serialize arrays and regular json.
Any help is appreciated.
Thanks & Regards,
Ertan
Hello,
I was more asking about (2) "IVAtBeginning" implementation. This is the part I could not figure.
Hello,
I am using Delphi 10.4.2, targeting Android32.
There is a previously developed REST web service with MARS Curiosity project which is using mORMot encryption routines. That web server running on Windows and is just fine. Now, I have to develop a small mobile application that is consuming some methods on that web service. Unfortunately, I failed to compile below function on Android32. I get error for SynLZ unit for its asm instructions. It uses SynCommons and SynCrypt units on Win32 platform.
function EncryptItAES(const s: string; const AKey: TBytes): string;
var
Key: TSHA256Digest;
Aes: TAESCFB;
_s: RawByteString;
begin
Result := EmptyStr;
Key := SHA256Digest(Pointer(AKey), Length(AKey));
Aes := TAESCFB.Create(Key, 256);
try
_s := StringToUTF8(s);
_s := BinToBase64(Aes.EncryptPKCS7(_s, True));
Result := UTF8ToString(_s);
finally
Aes.Free();
end;
end;
1) I wonder if I use mORMot2 encryption routines under Android32 and write similar function to above?
2) I can use alternative AES encryption library for Android32. I just don't know how above code each time produce different encrypt data for same input. I appreciate instructions on how to develop same logic using AES library that compiles under Android32? I am confused by checking sources to figure this out.
Thanks & Regards,
Ertan
Nevermind, just figured, right after I post that there is a space character in raw JSON string for
"isSelected "
Cost me a lot of time until I could actually see that.
Sorry for the noise.
Hello,
I am using Delphi 10.3, mORMot SynopseCommit.inc value '1.18.6244'
I could not figure why I get FAILED! message for following simple JSON string
{
"optionUuid": "57202ea4-cc62-4eff-bbea-fa5be41449ee",
"optionName": "Tuzsuz",
"optionPrice": 5.2,
"isSelected ": true
}
Using a code like below:
TOrderProductNote = packed record
optionUuid: string;
optionName: string;
optionPrice: Double;
isSelected: Boolean;
end;
procedure TForm2.Button1Click(Sender: TObject);
var
Response: TOrderProductNote;
TempString: string;
begin
TempString := '{"optionUuid": "57202ea4-cc62-4eff-bbea-fa5be41449ee","optionName": "Tuzsuz","optionPrice": 5.2,"isSelected ": true}';
if not SynCommons.RecordLoadJSON(Response, RawUTF8(TempString), TypeInfo(TOrderProductNote)) then
ShowMessage('FAILED!')
else
ShowMessage('OK');
end;
My debugging, I see de-serialization fails on "isSelected", but I could not understand why.
Any help is appreciated.
Thanks & Regards,
Ertan
Hello,
I tried to search in the forum without any success.
I receive a JSON string as following:
"lastPriceChangeDate": 1616569735683,
"lastStockChangeDate": 1618009761506,
"lastUpdateDate": 1618009761506,
This is a Unix Timestamp in milliseconds format.
Can I directly de-serialize that kind of values into to a TDateTime variable using mORMot?
Thanks & Regards,
Ertan
Hello,
I am trying to make an integration with an online food sale chain. They have kind of weird design. I am getting a JSON (part of it) as below:
"optionCategories": [
{
"optionCategory": "5dd28622e0450549407168f4",
"name": {
"tr": "1. Tantuni Tercihi",
"en": "1. Tantuni Tercihi"
},
"options": [
{
"option": "5dd28622e045052fb27168f6",
"product": "5dd28614c424f0658e8cedb8",
"name": {
"tr": "Yarım Ekmek Et Tantuni",
"en": "Yarım Ekmek Et Tantuni"
},
"price": 0,
"optionCategories": [
{
"optionCategory": "5dd28614c424f010da8cedb9",
"name": {
"tr": "Porsiyon Tercihi",
"en": "Porsiyon Tercihi"
},
"options": [
{
"option": "5dd28614c424f05bd58cedbc",
"name": {
"tr": "1 Porsiyon",
"en": "1 Porsiyon"
},
"price": 0
}
]
}
]
}
]
I could not figure how I should be preparing my record structure in order to be able to de-serialize something like that. I am actually stuck where "optionCategories" is becoming recursive. And there is another part where it is not going recursive. So, it is not always it is recursive, but sometimes. Here is an example for not recursive part (this also comes in identical array):
{
"optionCategory": "5dd28622e04505a7b37168ee",
"name": {
"tr": "İçecek Tercihi",
"en": "İçecek Tercihi"
},
"options": [
{
"option": "5dd28622e045052a3f7168ef",
"product": "5dd2861f35e9bba43d19b039",
"name": {
"tr": "Eker Ayran (300 ml)",
"en": "Eker Ayran (300 ml)"
},
"price": 0
}
]
}
My current record structure (part of it) is not working and is as following:
TName = packed record
tr: string;
en: string;
end;
TOption = packed record
option: string;
product: string;
name: TName;
price: Double;
end;
TOptions = TArray<TOption>;
TOptionCategory = packed record
optionCategory: string;
name: TName;
options: TOptions;
end;
TOptionCategories = TArray<TOptionCategory>;
I really do not want to parse whole JSON manually.
I appreciate any help.
Thanks & Regards,
Ertan
That worked just fine.
Pointer(TestBytes) generates identical hash.
Thank you.
Hello,
I am using Delphi 10.3.3, Synopse commit version 1.18.6045, generating Win32 executable.
I had some legacy code that I am modifying. I used to pass parameter as array of byte and now I am changing it into TBytes. However, I am getting different result for same byte values. My test code is as following:
uses
SynCrypto;
const
TestArray: Array [0..5] of Byte = (1, 2, 3, 4, 5, 6);
TestBytes: TBytes = [1, 2, 3, 4, 5, 6];
procedure TForm1.Button1Click(Sender: TObject);
var
Sha2561: TSHA256Digest;
Sha2562: TSHA256Digest;
begin
Sha2561 := SHA256Digest(Pointer(@TestArray), SizeOf(TestArray));
Sha2562 := SHA256Digest(Pointer(@TestBytes), Length(TestBytes)); // For TBytes I must use Length, SizeOf always returns 4
if not CompareMem(@Sha2561, @Sha2562, 32) then
ShowMessage('different')
else
ShowMessage('identical');
end;
For above test, I get different message displayed.
I am not sure if I am doing something wrong. I could not remember why I did write a code like
Pointer(@TestArray)
That code is possibly a copy-paste from this forum, years ago. In any way, using it as
@TestArray
also displays different message for me.
Any help is appreciated.
Thanks & Regards,
Ertan
Missed that point in samples.
Thanks for clarifying.
Hello,
I am using Delphi 7 and latest available version of Synopse from GitHub. Just removed all SynCommons.pas files from my system and have just a single copy.
Registering a custom json text writer fails for me. Details are as following:
type
TTicker = packed record
symbol: RawUTF8;
highPrice: Double;
lowPrice: Double;
end;
TTickers = Array of TTicker;
const
__TTickers = '[symbol RawUTF8 highPrice Double lowPrice Double]';
initialization
TTextWriter.RegisterCustomJSONSerializerFromText(TypeInfo(TTickers), __TTickers);
end;
I am getting error saying:
TTicker text definition is not accurate, or the type has not been defined as packed record: RTTI size is 20 bytes but text definition covers 0 bytes
I cannot see where I am doing it wrong.
Any help is appreciated.
Thanks & regards,
Ertan
Thanks for all suggestions.
Actually, I did take very basic precautions like try..except block in my code. I did not put it all here in my earlier post.
...
try
V := _Json(RetJsonString);
except
// do what needs to be done
end;
...
After reading other replies, I also changed my code to retrieve data like following:
var
Amount: Integer;
LStPayment: TVariantDynArray;
begin
LStPayment := _Safe(V.stPayment).Values;
for Idx := 0 to High(LStPayment) do
begin
if LStPayment[Idx].typeOfPayment = 4 then
begin
Amount := LStPayment[Idx].StBankPayment.Amount;
end;
end;
end;
Which IMHO is easier to compared to my initial version. However, I am not quite sure this code above is free from exceptions if there is no StBankPayment exists in LStPayment (even though it should exists because payment type 4 means credit card payment) I am asking just in case. Because even rarely it does happen when company does an update to device software and breaks produced json in a way.
I appreciate if someone can confirm/deny.
Regards,
Ertan
Seems I need to use array access as following:
...
V := _Json(RetJsonString);
...
var
Amount: Integer;
AType: Integer;
begin
if V.StPayment._(0).typeOfPayment = 4 then
begin
Amount := V.StPayment._(0).StBankPayment.Amount;
end;
end;
Problem solved.
Thanks.
That did indeed work.
I gave up and follow igors233 suggestion. As I do not know how to use TDocVariantData. I did read documents but could not comprehend them fast enough. So, I went down using Variant.
However, I could failed to read information I am looking for from sub objects in incoming json. For regular record filled with data I could write something like:
var
Amount: Integer;
AType: Integer;
begin
if Rec.StPayment[0].typeOfPayment = 4 then
begin
Amount := Rec.StPayment[0].StBankPayment.Amount;
end;
Now, I load json into a Variant named V. Try to write a code as below:
...
V := _Json(RetJsonString);
...
var
Amount: Integer;
AType: Integer;
begin
if V.StPayment[0].typeOfPayment = 4 then
begin
Amount := V.StPayment[0].StBankPayment.Amount;
end;
That compiles fine, but fails at the if statement at run-time.
I appreciate some examples as to how I can extract json data directly from a variant.
Thanks & regards,
Ertan
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;
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;
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;
Hello,
I have a problem de-serializing a json string. After I get false from de-serialization function, I see some variables have value in my record.
In order to find my mistake, I would like to understand how mORMot doing de-serializing order.
For example I have below json string:
{"name":"test","surname":"test"}
And my record definition is:
type
TPerson = packed record
surname: string;
name: string;
end;
When de-serializing, is it name or surname that is filled in record variable first?
Thanks & regards,
Ertan
I do really would like to hear if somebody can re-produce issue I am facing.
I could complete a small project and I observe same problem in that stand-alone project.
Project can be downloaded from here: https://fil.email/qYgVeiEo
P.S.: Download valid for 1 month only.
FYI, I am using Synopse from GitHub. However, I am using SVN client to get sources. I see my copy is from 26th January, 2020. There is note "Merge pull request #268 from LongDirtyAnimAlf/master fix compilation of Alpine Linux."
I am going to work on a small project to re-produce (if I can re-produce) and either post project or a feedback here. That is in a few days.
Thanks.
In provided test json stLoyaltyService is null. However, when I put its text definition in the middle, it is not empty but filled in with A letters I suppose. There are other problems as well. For example, UserData variable is not filled in even there is a value in the json string for it.
Please see: https://imgur.com/a/lsjTnsM
Note that stLoyaltyService[...] defines a nested ARRAY [..] of records.
I realize that I did not share all necessary info. Sorry about that.
I indeed have this record as an array of records in my definition:
TStLoyaltyServiceInfo = packed record
name: Array[0..23] of Byte; // original was this. I changed to "Array of byte" after having access violation errors
CustomerId: string;
ServiceId: UInt16;
u16AppId: UInt16;
CustomerIdType: UInt16;
TotalDiscountAmount: UInt32;
end;
TStLoyaltyServiceInfos = Array of TStLoyaltyServiceInfo;
...
TStTicket = packed record
...
stLoyaltyService: TStLoyaltyServiceInfos; // [0..MAX_LOYALITY_TRANS_NUMBER]
end;
So, I believe my definition of "array of records" matches in my text definition. It is just changing position other than last most in the definition leads to a memory leak in my code. Maybe it is my code to blame I do not know for sure. Just trying to understand.
I also tried to use TByteDynArray and if definition is not latest, I still get access violation.
My complete text definition is here: https://pastebin.com/u27beRi9 (Where I put it at the end)
Text definition that gives access violation is here: https://pastebin.com/kACw9Y1z (Where it is defined in the middle)
And if you check both above that is what I mean by "in the middle" or "at the end" or "bottom most (last)"
Formatted json string is here: https://pastebin.com/9NxWvx4v
De-Serialized (single line in text file) json string is here: https://pastebin.com/wQsqjtVQ
Above two are same except one is formatted by online website.
Complete (hopefully I did not forget anything) record definitions are here: https://pastebin.com/uyb2uaam
That QWord works for UInt64. Thank you.
I have one thing I would like to understand though.
I have below sub-record. If I move that record definition up in my text definition, that gets me memory corruption (access violation) after de-serialization before exiting procedure and corruption goes away if put it bottom most (last) in my text definition.
TStLoyaltyServiceInfo = packed record
name: Array of Byte;
CustomerId: string;
ServiceId: UInt16;
u16AppId: UInt16;
CustomerIdType: UInt16;
TotalDiscountAmount: UInt32;
end;
For above record I have following text definition:
stLoyaltyService[name Array of Byte CustomerId string ServiceId Word u16AppId Word CustomerIdType Word TotalDiscountAmount Cardinal]
For the record, stLoyaltyService is NULL in my de-serialized json string. So, basically it should not have any items at all. But, I see some items are created after de-serialization in Local variable view *if* it is in the middle but not at the end in my text definition.
It is possible I am missing something here?
Thanks & regards,
Ertan