AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Json Serializer und GUID

Ein Thema von backdraft · begonnen am 18. Jun 2021 · letzter Beitrag vom 18. Jun 2021
Antwort Antwort
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.079 Beiträge
 
Delphi 10.4 Sydney
 
#1

AW: Json Serializer und GUID

  Alt 18. Jun 2021, 10:55
Es liegt, wie jaenicke andeutet, an der Typ-Definition für D4.
Das array[0..7] of Byte bekommt die Rtti nicht als Typ aufgedröselt.
Vielleicht ein Bug, weil anscheinend die Rtti immer einen richtigen Alias-Namen braucht.
Beim Erstellen des notwendigen TRttiField für D4, wird der FFieldType nicht ordentlich aufgelöst.
Die PTypeInfo dafür müsste als TTypeKind.tkArray rauskommen.
Delphi-Quellcode:
constructor TRttiField.Create(APackage: TRttiPackage; AParent: TRttiObject;
  var P: PByte);
begin
  inherited Create(APackage, AParent, P);
  FFieldType := GetFieldType; // hier kommt nil zurück für statische Arrays.
  FOffset := GetOffset;
end;
...
function TRttiRecordField.GetFieldType: TRttiType;
begin
  Result := Pool.TypeOrNil(Handle^.Field.TypeRef); //TypeRef ist hier nil, daher kommt von TypeOrNil auch nichts zurück. Das passiert schon beim Erzeugen des Basis-Typs TRttiObject im constructor
end;
Darum ist in TJsonSerializerWriter.WriteProperty in Zeile 1361 AProperty.Contract := ResolveContract(AProperty.TypeInf); der Wert für AProperty.TypeInf nil und es kommt kein vernünftiger Contract: TJsonContract bei raus.

Du kannst dich zumindest dahingehend behelfen, indem du dir einen Hilftyp zusammen schusterst und später dann immer zwischen deinen GUID-Typ und den richtigen TGUID-Typ aus der RTL castest:

Konsolenbeispiel:
Delphi-Quellcode:
program Project6;

{$APPTYPE CONSOLE}
{$R *.res}

uses
    System.SysUtils,
    System.Classes,
    System.JSON,
    System.JSON.Serializers;

type
    // TMyGUID = TGUID;
    TMyArray = array [0 .. 7] of Byte;

    TMyGUID = record
    public
        D1: Cardinal;
        D2: Word;
        D3: Word;
        D4: TMyArray;
        class function NewGuid: TMyGUID; static;
        function ToString: string;
    end;

class function TMyGUID.NewGuid: TMyGUID;
var
    foo: TGUID;
begin
    foo := TGuid.NewGuid;
    Result.D1 := foo.D1;
    Result.D2 := foo.D2;
    Result.D3 := foo.D3;
    Result.D4 := TMyArray(foo.D4);
end;

function TMyGUID.ToString: string;
begin
    Result := TGuid(Self).Tostring;
end;

var
    lGuid, lNewGuid: TMyGUID;
    lText: TStringList;
    lJson: string;
    lSerializer, lDeserializer: TJsonSerializer;

begin
    try
        lText := TStringList.Create;
        try
            lGuid := TMyGUID.NewGuid;
            lText.Add(lGuid.ToString);

            lSerializer := TJsonSerializer.Create;
            try
                lJson := lSerializer.Serialize<TMyGUID>(lGuid);
            finally
                FreeAndNil(lSerializer);
            end;

            lText.Add(lJson);

            lDeserializer := TJsonSerializer.Create;
            try
                lNewGuid := lDeserializer.Deserialize<TMyGUID>(lJson);
            finally
                FreeAndNil(lSerializer);
            end;

            lText.Add(lNewGuid.ToString);

            Writeln(lText.Text);
        finally
            FreeAndNil(lText);
        end;
    except
        on E: Exception do
            Writeln(E.ClassName, ': ', E.Message);
    end;
    Readln;
end.
Über den Call Stack TJsonDefaultContractResolver.ResolveContract | TJsonDefaultContractResolver.CreateContract | TJsonDefaultContractResolver.CreateArrayContract wird eine Instanz von TJsonArrayContract erzeugt, mit der die Serialisierung arbeiten kann.
  Mit Zitat antworten Zitat
Benutzerbild von Stevie
Stevie

Registriert seit: 12. Aug 2003
Ort: Soest
4.051 Beiträge
 
Delphi 10.1 Berlin Enterprise
 
#2

AW: Json Serializer und GUID

  Alt 18. Jun 2021, 13:59
Einfach nen Konverter für TGUID schreiben und am Serializer hinzufügen, fertig:

Delphi-Quellcode:
type
  TGUIDConverter = class(TJsonConverter)
  public
    function CanConvert(ATypeInfo: PTypeInfo): Boolean; override;
    function ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo; const AExistingValue: TValue;
      const ASerializer: TJsonSerializer): TValue; override;
    procedure WriteJson(const AWriter: TJsonWriter; const AValue: TValue;
      const ASerializer: TJsonSerializer);override;
  end;

function TGUIDConverter.CanConvert(ATypeInfo: PTypeInfo): Boolean;
begin
  Result := ATypeInfo = System.TypeInfo(TGUID);
end;

function TGUIDConverter.ReadJson(const AReader: TJsonReader;
  ATypeInf: PTypeInfo; const AExistingValue: TValue;
  const ASerializer: TJsonSerializer): TValue;
begin
  Result := TValue.From(TGuid.Create(AReader.Value.AsString));
end;

procedure TGUIDConverter.WriteJson(const AWriter: TJsonWriter;
  const AValue: TValue; const ASerializer: TJsonSerializer);
begin
  AWriter.WriteValue(AValue.AsType<TGUID>);
end;

type
  TFooBar = class
    GUID: TGUID;
  end;
procedure Main;
begin
  var foobar := TFooBar.Create;
  foobar.GUID := TGUID.NewGuid;
  Writeln(foobar.GUID.ToString);

  var lSerializer := TJsonSerializer.Create;
  lSerializer.Converters.Add(TGUIDConverter.Create);

  var lJson := lSerializer.Serialize(foobar);

  Writeln(lJson);

  var newFooBar := lSerializer.Deserialize<TFooBar>(lJson);
  Writeln(newFooBar.GUID.ToString);
end;
Stefan
“Simplicity, carried to the extreme, becomes elegance.” Jon Franklin

Delphi Sorcery - DSharp - Spring4D - TestInsight
  Mit Zitat antworten Zitat
TiGü

Registriert seit: 6. Apr 2011
Ort: Berlin
3.079 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: Json Serializer und GUID

  Alt 18. Jun 2021, 14:40

Leider kein :huld: Smiley!


@backdraft: Aber dann den eigenen Konverter noch freigeben, dass fehlt in Stevies Beispiel.
  Mit Zitat antworten Zitat
backdraft

Registriert seit: 19. Apr 2005
Ort: Hückeswagen
339 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Json Serializer und GUID

  Alt 18. Jun 2021, 14:52
Ja vielen Dank.
Klappt perfekt.
Auf die Idee, dass ein einfach eine Converterproperty gibt bin ich nicht gekommen.
Ich dachte man kann es irgendwie über der Variable definieren mit [].
Läuft bestens.
Oliver
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 02:18 Uhr.
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz