#1 2018-11-15 17:34:22

mohsenti
Member
Registered: 2015-04-11
Posts: 72

RegisterCustomSerializerFieldNames bug

Hi,

It seems RegisterCustomSerializerFieldNames has a bug when I use more than one custom field name for more than one class.
The second register will override the first one and it is odd because they are different classes.
I can't use record serialization because inheritance is a need.

program project1;

uses
  SynCommons,
  mORMot;

type

  { TBaseClass }

  TBaseClass = class(TSynAutoCreateFields)
  private
    fName: string;
  published
    property Name: string read fName write fName;
  end;

  { TClass1 }

  TClass1 = class(TBaseClass)
    private
      ftype_: string;
    published
      property type_: string read ftype_ write ftype_;
  end;

  { TClass2 }

  TClass2 = class(TBaseClass)
    private
      fclass_: string;
    published
      property class_: string read fclass_ write fclass_;
  end;

  { TTestClass }

  TTestClass = class(TSynAutoCreateFields)
  private
    fCount: integer;
    fObject1: TClass1;
    fObject2: TClass2;
  published
    property Count: integer read fCount write fCount;
    property Object1: TClass1 read fObject1;
    property Object2: TClass2 read fObject2;
  end;

var
  JsonString: RawUTF8;
  Obj: TTestClass;

begin
  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass1, ['type_'], ['type']);
  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass2, ['class_'], ['class']);
  JsonString := '{"Count":2,"Object1":{"Name":"C1","type_":"TYPE"},"Object2":{"Name":"C2","class_":"CLASS"}}';
  Obj := TTestClass.Create;
  WriteLn(ObjectLoadJSON(Obj, JsonString, nil, JSONTOOBJECT_TOLERANTOPTIONS));
  WriteLn(ObjectToJSON(Obj, [woHumanReadable]));
  Obj.Free;
  ReadLn;
end.

Offline

#2 2018-11-21 04:38:40

Ehab
Member
Registered: 2016-09-07
Posts: 15

Re: RegisterCustomSerializerFieldNames bug

Hi mohsenti

In the help of the function it says :
note that any inherited classes will be serialized as the parent class

   .....................................................

    // - note that any inherited classes will be serialized as the parent class
    // - this method is thread-safe, but should be called before any serialization
    class procedure RegisterCustomSerializerFieldNames(aClass: TClass;
      const aClassFields, aJsonFields: array of ShortString);

I think this mean that your last TJSONSerializer.RegisterCustomSerializerFieldNames only applied.

I noticed also that JsonString content in your example is not valid since you called RegisterCustomSerializerFieldNames

  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass1, ['type_'], ['type']);
  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass2, ['class_'], ['class']);
  JsonString := '{"Count":2,"Object1":{"Name":"C1","type_":"TYPE"},"Object2":{"Name":"C2","class_":"CLASS"}}';

//It must be

  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass1, ['type_'], ['type']);
  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass2, ['class_'], ['class']);
  JsonString := '{"Count":2,"Object1":{"Name":"C1","type":"TYPE"},"Object2":{"Name":"C2","class":"CLASS"}}';

I hope ab, can find some time to implement it.

Last edited by Ehab (2018-11-21 04:41:32)

Offline

#3 2018-11-26 15:14:58

mohsenti
Member
Registered: 2015-04-11
Posts: 72

Re: RegisterCustomSerializerFieldNames bug

Thank you Ehab.
Yes you are right about the JSON, but the problem is still there.
TClass1 and TClass2 are inherited from same class but I checked with different classes that inherited from TSynAutoCreateFields and RegisterCustomSerializerFieldNames will use only the last custom serializer.
@ab , can you validate this?

Offline

#4 2018-11-26 15:56:47

Ehab
Member
Registered: 2016-09-07
Posts: 15

Re: RegisterCustomSerializerFieldNames bug

I think you need to report a bug to @ab

Offline

#5 2018-11-26 16:04:20

mohsenti
Member
Registered: 2015-04-11
Posts: 72

Re: RegisterCustomSerializerFieldNames bug

Yes, so I will wait for him to validate my findings.

Offline

#6 2018-12-02 16:11:49

mohsenti
Member
Registered: 2015-04-11
Posts: 72

Re: RegisterCustomSerializerFieldNames bug

@ab I found the bug, it was because of pointers.
I solved it temporarily.

@@ -49046,7 +49046,7 @@ type
     Reader: TJSONSerializerCustomReader;
     Writer: TJSONSerializerCustomWriter;
     Props: PPropInfoDynArray;
-    Fields: PShortStringDynArray; // match Props[] order
+    Fields: TShortStringDynArray; // match Props[] order
     Kind: TJSONObject;
   end;
   TJSONCustomParsers = array of TJSONCustomParser;
@@ -49136,7 +49136,7 @@ var i: integer;
 begin
   if Parser^.Props<>nil then begin // search from RegisterCustomSerializerFieldNames()
     for i := 0 to length(Parser^.Fields)-1 do
-      if IdemPropNameU(Parser^.Fields[i]^,PropName,PropNameLen) then begin
+      if IdemPropNameU(Parser^.Fields[i],PropName,PropNameLen) then begin
         result := Parser^.Props[i];
         exit;
       end;
@@ -49148,7 +49148,7 @@ end;
 class procedure TJSONSerializer.RegisterCustomSerializerFieldNames(aClass: TClass;
   const aClassFields, aJsonFields: array of ShortString);
 var prop: PPropInfoDynArray;
-    field: PShortStringDynArray;
+    field: TShortStringDynArray;
     n,p,f: integer;
     found: boolean;
     parser: PJSONCustomParser;
@@ -49167,7 +49167,7 @@ begin
     for f := 0 to high(aClassFields) do // check customized field name
       if IdemPropName(prop[p].Name,aClassFields[f]) then begin
         if aJsonFields[f]<>'' then begin // '' to ignore this property
-          field[n] := @aJsonFields[f];
+          field[n] := aJsonFields[f];
           prop[n] := prop[p];
           inc(n);
         end;
@@ -49175,7 +49175,7 @@ begin
         break;
       end;
     if not found then begin // default serialization of published property
-      field[n] := @prop[p].Name;
+      field[n] := prop[p].Name;
       prop[n] := prop[p];
       inc(n);
     end;
@@ -52475,7 +52475,7 @@ begin
         raise EParsingException.CreateUTF8('%.WriteObject woDontStoreInherited '+
           'after RegisterCustomSerializerFieldNames(%)', [self,aClassType]) else
         for i := 0 to length(parser^.Props)-1 do begin
-          CustomPropName := parser^.Fields[i];
+          CustomPropName := @parser^.Fields[i];
           WriteProp(parser^.Props[i]);
         end;
   end else

Last edited by mohsenti (2018-12-02 16:12:25)

Offline

#7 2018-12-03 13:52:44

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,240
Website

Re: RegisterCustomSerializerFieldNames bug

Thanks a lot for the feedback!

Please check https://synopse.info/fossil/info/d513678b44

Offline

#8 2018-12-03 20:22:25

mohsenti
Member
Registered: 2015-04-11
Posts: 72

Re: RegisterCustomSerializerFieldNames bug

Thanks you very much ab.
Can I ask why TShort63?

Offline

#9 2018-12-04 08:35:45

ab
Administrator
From: France
Registered: 2010-06-21
Posts: 14,240
Website

Re: RegisterCustomSerializerFieldNames bug

To take less memory... premature optimization for sure. wink

Offline

#10 2018-12-05 07:32:45

mohsenti
Member
Registered: 2015-04-11
Posts: 72

Re: RegisterCustomSerializerFieldNames bug

Great, Thanks.

Offline

Board footer

Powered by FluxBB