#1 2022-02-17 13:40:25

okoba
Member
Registered: 2019-09-29
Posts: 120

Unserializing custom array of classes with mORMot2

I had a code with mORMot1 like:

  TTextWriter.RegisterCustomJSONSerializer(TypeInfo(TItems), @ReadItem, nil);

and

 
function TItemReader.ReadItem(P: PUTF8Char; var AValue; out AValid: boolean): PUTF8Char;
var
  V: TObject absolute AValue;
  OldP, S: PUTF8Char;
  SP: RawUTF8;
  L: integer;
begin
  AValid := False;
  Result := nil;
  if P = nil then
    Exit;
  OldP := P;
  P := JsonObjectItem(P, 'CustomClass');
  if P = nil then
    raise Exception.Create('Invalid Item');
  JSONRetrieveStringField(P, S, L, False);
  SetString(SP, S, L);
  case SP of
    'ItemA': V := TItemA.Create;
    'ItemB': V := TItemB.Create;
    else
      raise Exception.Create('Unknown Item: ' + SP);
  end;
  AValid := True;
  Result := JSONToObject(AValue, OldP, AValid, nil, JSONTOOBJECT_TOLERANTOPTIONS);
end;

and now with mORMot2, I can not convert it.
I thought I should do this but it leads to unknown errors.

 
function TItemReader.ReadItem(P: PUTF8Char; var AValue; out AValid: boolean): PUTF8Char;
var
  V: TObject absolute AValue;
  OldP, S: PUTF8Char;
  SP: RawUTF8;
  L: integer;
begin
  AValid := False;
  Result := nil;
  P := Context.Json;
  OldP := P;
  P := JsonObjectItem(P, 'CustomClass');
  if P = nil then
    raise Exception.Create('Invalid Item');
  JSONRetrieveStringField(P, S, L, False);
  SetString(SP, S, L);
  case SP of
    'ItemA': V := TItemA.Create;
    'ItemB': V := TItemB.Create;
    else
      raise Exception.Create('Unknown Item: ' + SP);
  end;
  AValid := True;
  Context.Json := JSONToObject(Instance, Context.Json, Context.Valid, nil, JSONTOOBJECT_TOLERANTOPTIONS);     
end;

What is the correct way to unserializing and array of classes?
Note: I can not use ParseNewObject, as the CustomClass property may not be the first properties and some other custom needs.

Offline

#2 2022-02-19 16:20:41

okoba
Member
Registered: 2019-09-29
Posts: 120

Re: Unserializing custom array of classes with mORMot2

Here is my response to my question. I do not know if this is the best option though.


procedure TItemReader.ReadItem(var Context: TJsonParserContext; Data: pointer);   
var
  S: PUTF8Char;
  SP: RawUTF8;
  L: integer;
  C: TItemClass;
  Instance: TObject;   
begin
  Result := nil;
  P := Context.Json;
  OldP := P;
  P := JsonObjectItem(P, 'CustomClass');
  if P = nil then
    raise Exception.Create('Invalid Item');
  JSONRetrieveStringField(P, S, L, False);
  SetString(SP, S, L);
  case SP of
    'ItemA': C := TItemA;
    'ItemB': C := TItemB;
    else
      raise Exception.Create('Unknown Item: ' + SP);
  end;
  Context.Info := Rtti.RegisterClass(C);
  Instance := TRttiJson(Context.Info).ParseNewInstance(Context);           
end;

And register it like this:

TRttiJson.RegisterCustomSerializer(TypeInfo(TItem), @ReadItem, nil);   

Last edited by okoba (2022-02-19 20:57:09)

Offline

#3 2022-02-19 20:55:02

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

Re: Unserializing custom array of classes with mORMot2

C is set nowhere in your code.

I wonder how it may work.

Offline

#4 2022-02-19 20:58:41

okoba
Member
Registered: 2019-09-29
Posts: 120

Re: Unserializing custom array of classes with mORMot2

It was a copy and paste issue, fixed it.
Is the style of the solution correct? Registering the class and using ParseNewInstance?

Offline

#5 2022-02-19 21:53:29

tbo
Member
Registered: 2015-04-20
Posts: 353

Re: Unserializing custom array of classes with mORMot2

Shouldn't it be called that?

TRttiJson.RegisterCustomSerializer(TypeInfo(TItem), TItemReader.ReadItem, nil); 

Examples can be found in the test units for mORMot2.

Maybe it's better to first describe what you actually want to do (what the data structure you want to serialize looks like) and not how you do it.

With best regards
Thomas

Offline

Board footer

Powered by FluxBB