Einzelnen Beitrag anzeigen

Whookie

Registriert seit: 3. Mai 2006
Ort: Graz
441 Beiträge
 
Delphi 10.3 Rio
 
#1

TJsonSerializer und polymorphes Array?

  Alt 8. Mär 2021, 14:23
Hallo zusammen, ich habe gerade mit TJsonSerializer experimentiert und bin auf folgendes Problem gestoßen:

Delphi-Quellcode:
Type
  TMyKind = (mkA, mkB);

  [JsonSerialize(TJsonMemberSerialization.&In)]
  TBaseData = Class
    [JSonIn]
    [JsonName('Kind')]
    Kind: TMyKind;
    constructor Create; virtual;
  End;

  [JsonSerialize(TJsonMemberSerialization.&In)]
  TAData = Class(TBaseData)
    [JsonIn]
    Name: String;
    constructor Create; override;
  End;

  [JsonSerialize(TJsonMemberSerialization.&In)]
  TBData = Class(TBaseData)
    [JsonIn]
    Group: String;
    [JsonIn]
    Text: String;
    constructor Create; override;
  End;


  [JsonSerialize(TJsonMemberSerialization.&In)]
  TMyData = Class
    [JsonIn]
    [JsonObjectHandling(TJsonObjectHandling.Reuse)]
    Data: TArray<TBaseData>;

    [JsonIn]
    MainData: TBaseData;

    constructor Create; virtual;
    Destructor Destroy; override;
  End;


...

{ TMyData }

constructor TMyData.Create;
begin
  inherited;
  SetLength(Data, 2);
  Data[0] := TAData.Create;
  Data[1] := TBData.Create;
  MainData := TBData.Create;
end;
Ich habe also ein Data[] das eine TAData und eine TBData instanz enthält. Beim serialisieren funktioniert das wunderbar:

Delphi-Quellcode:
  fMyData := TMyData.Create;

  js := TJsonSerializer.Create;
  js.Formatting := TJsonFormatting.Indented;
  s := js.Serialize(fMyData);
  ...
  Memo.Text := s;
Code:
{
    "Data": [
        {
            "Name": "A",
            "Kind": 1
        },
        {
            "Group": "B",
            "Text": "C",
            "Kind": 0
        }
    ],
    "MainData": {
        "Group": "D",
        "Text": "E",
        "Kind": 1
    }
}
Beim Versuch dieses JSON mit Populate wieder einzulesen wird dann aber das Array neu erzeugt (alle Elemente vom Typ TBaseData).

Delphi-Quellcode:
  LMyData := TMyData.Create;
  js := TJsonSerializer.Create;
  js.Populate<TMyData>(Memo.Text, LMyData);
  // LMyData.Data[0] = TBaseData
  // LMyData.Data[1] = TBaseData
  // LMyData.MainData = TBData
  ...
  Memo.Text := js.Serialize(LMyData)
Das ergibt nach erneuter Serialisierung:
Code:
{
    "Data": [
        {
            "Kind": 1
        },
        {
            "Kind": 0
        }
    ],
    "MainData": {
        "Group": "D",
        "Text": "E",
        "Kind": 1
    }
}
Ich hatte allerdings gehofft, dass durch Angabe von JsonObjectHandling(TJsonObjectHandling.Reuse) die übergebenen Instanzen erhalten bleiben.

Frage 1: Gibt es eine Möglichkeit, die korrekten Typen für die Array-Elemente zu erhalten?
Frage 2: Kann man die Reihenfolge in der js.Serialize den Ausgabestring erzeugt umdrehen (geerbte Properies zuerst -> "Kind" vor "Name")?
Whookie

Software isn't released ... it is allowed to escape!
  Mit Zitat antworten Zitat