#1 2017-04-03 08:17:08

Del
Member
Registered: 2017-03-24
Posts: 20

Custom serializer reader to return objectlist

I have a json string containing a collection of objects that I want to read into an object list. Are then any examples that showcase this behaviour? Essentially just like jsontoobject using a objectlist but with the ability to customize field mappings.

Offline

#2 2017-04-05 15:25:02

George
Member
Registered: 2016-04-05
Posts: 142

Re: Custom serializer reader to return objectlist

Hello!

I have simple test case, that probably can help you.
TObjectList - serialization and deserialization works as expected.
Also, i included code that should map fields, but that not works, last line of code (commented).

Personally i have question about generic version of TObjectList<T>.
With similar usage, serialized text not contain objects (that behavior included in test case), while documentation says:

You could also create a TObjectList, or - even better for newer versions of Delphi supporting the generics syntax - a TObjectList<T>

  {$M+}
  TCustomClass = class
  private
    FField1: RawUTF8;
    FField2: RawUTF8;
  published
    property Field1: RawUTF8 read FField1 write FField1;
    property Field2: RawUTF8 read FField2 write FField2;
  end;
  {$M-}
procedure TForm1.Serialize();
var
  i: Integer;
  CustomClassObject: TCustomClass;
  CustomClassList: TObjectList;
begin
  CustomClassList := TObjectList.Create(True);
  // fill test data
  for i := 0 to 4 do
    begin
      CustomClassObject := TCustomClass.Create();
      CustomClassObject.FField1 := 'value ' + StringToUTF8(i.ToString);
      CustomClassObject.FField1 := 'another value ' + StringToUTF8(i.ToString);
      // TObjectList
      CustomClassList.Add(CustomClassObject);
    end;
  // Serialize and show results in memo
  MemoObjectList.Lines.Text := UTF8ToString(ObjectToJSON(CustomClassList, [woStoreClassName, woHumanReadable]));
  // Cleanup
  CustomClassList.Free();
  // Additional generic serialization test
  MemoGenericObjectList.Lines.Text := UTF8ToString(GenSerializationTest.DoSerializeTest());
end;
initialization

// TJSONSerializer.RegisterCustomSerializerFieldNames(TCustomClass, ['field1', 'field2'], ['RenamedField1', 'RenamedField2']);

Last edited by George (2017-04-10 09:02:51)

Offline

#3 2017-04-06 10:21:03

George
Member
Registered: 2016-04-05
Posts: 142

Re: Custom serializer reader to return objectlist

Personally i have question about generic version of TObjectList<T>.

Found answer here: https://synopse.info/forum/viewtopic.php?id=2943

Offline

#4 2017-04-06 21:32:07

George
Member
Registered: 2016-04-05
Posts: 142

Re: Custom serializer reader to return objectlist

George wrote:

Personally i have question about generic version of TObjectList<T>.

Found answer here: https://synopse.info/forum/viewtopic.php?id=2943

Not like dependency on REST.Json.
So, i've changed test case code to use mORMot functionality for TObjectList<TCustomObjectForGenerics> serialization / deserialization.
There is memory leak in JSONToObject, when json text is not correct.

Last edited by George (2017-04-06 21:34:38)

Offline

#5 2017-04-10 09:01:22

George
Member
Registered: 2016-04-05
Posts: 142

Re: Custom serializer reader to return objectlist

Test project updated, now looks more simple, use TObjectList serialization to serialize/deserialize TObjectList<T> objects.

Offline

#6 2017-04-10 15:14:02

George
Member
Registered: 2016-04-05
Posts: 142

Re: Custom serializer reader to return objectlist

Can anyone help with complicated class deserialization (UnitComplicatedObjectSerializationTest)?
Added test case with class that include TObjectList fields with nested objects that include another TObjectList.
Serialization works well, but i can't restore objects from json. I've used documentation that says:

won't handle TObjectList (even if ObjectToJSON is able to serialize them) since has no way of knowing the object type to add (TCollection.Add is missing), unless: 1. you set the TObjectListItemClass property as expected, and provide a TObjectList object, or 2. woStoreClassName option has been used at ObjectToJSON() call and the corresponding classes have been previously registered by TJSONSerializer.RegisterClassForJSON()

Both conditions are implemented, but without luck.

Offline

#7 2017-04-13 15:06:59

George
Member
Registered: 2016-04-05
Posts: 142

Re: Custom serializer reader to return objectlist

Welcome back to my blog smile

I updated test/demo project with TDocVariant (with TDocVariantData) use case.
Works good, TDocVariant is very powerful part of framework.. Again, not simple as pie, but check the demo and don't forget that every mORMot method well commented.

Last edited by George (2017-04-13 17:59:41)

Offline

#8 2017-04-13 15:30:31

George
Member
Registered: 2016-04-05
Posts: 142

Re: Custom serializer reader to return objectlist

AB, can you take a look at this module to approve that it use TDocVariant by design?

There is 4 classes for serialization / deserialization:
TComplicatedClass
TCustomObjectWithNestedObjLists
TSimpleObjectOne
TSimpleObjectTwo

One class to execute test:
TComplSerializationWithTDocVariantTest

I have one place where i can't add array item by reference:

class function TComplicatedClass.SerializeAsVariant(ComplicatedClass: TComplicatedClass): Variant;
var
  idx: Int64;
  CustomObjectWithNestedObjLists: TCustomObjectWithNestedObjLists;
  VObj: Variant;
begin
  with TDocVariantData(Result) do
    begin
      // Init result
      InitObject([], DocVariantOptionsForSerialization);
      // Add class info
      AddValue('className', Self.QualifiedClassName);
      // Add data
      { Name }
      AddValue('name', ComplicatedClass.Name);
      { field1 }
      // add empty array, to save items from TObjectList<T>
      idx := AddValue('field1', _Arr([], DocVariantOptionsForSerialization));
      // direct access to field2 by index by reference
      with _safe(Value[idx], dvArray)^ do
        // serialize ComplicatedClass.Field1 per item and add it to array
        for CustomObjectWithNestedObjLists in ComplicatedClass.Field1 do
          begin
            VObj := TCustomObjectWithNestedObjLists.SerializeAsVariant(CustomObjectWithNestedObjLists);
            
            AddItem(VObj); // << Here VObj is Variant with TDocVariant object
            VObj := Unassigned; // Without this line i have memory leaks, so AddItem() not owning VObj as i want.

          end;
    end;
end;

Last edited by George (2017-04-13 16:19:09)

Offline

Board footer

Powered by FluxBB