AGB  ·  Datenschutz  ·  Impressum  







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

Erfahrungen mit TJsonSerializer

Ein Thema von Incocnito · begonnen am 7. Aug 2025 · letzter Beitrag vom 8. Aug 2025
Antwort Antwort
Seite 2 von 2     12   
Incocnito

Registriert seit: 28. Nov 2016
237 Beiträge
 
#11

AW: Erfahrungen mit TJsonSerializer

  Alt 8. Aug 2025, 15:23
Wer das einmal selbst nachstellen möchte, hier einmal der Code meiner Test-Unit:
Delphi-Quellcode:
unit JsonSerializerAnalyse;

interface

uses
  System.SysUtils, System.Classes, System.JSON.Serializers,
  System.JSON.Types, Rest.Json, System.Diagnostics,
  System.TimeSpan, System.JSON.Readers, System.JSON.Writers,
  System.Rtti, System.TypInfo;

// Externe Aufruf-Prozedur
procedure RunAllTests();
//Procedure FinalTest(var Results: TStringList);

type
  // Gemeinsames Interface für alle Test-Klassen
  ITestJsonClass = interface
    ['{E62D3704-A6B9-4B05-94A4-553C6FD818AA}']
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
  end;

  // Test B: Custom Boolean Converter
  TCustomBooleanConverter = class(TJsonConverter)
  public
    function CanConvert(ATypeInf: 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;

  // Test C: Smart Contract Resolver - behandelt F-Prefix automatisch
  TDelphiFieldContractResolver = class(TJsonDefaultContractResolver)
  protected
    function ResolvePropertyName(const AName: string): string; override;
  public
    constructor Create(); overload;
    constructor Create(AMemberSerialization: TJsonMemberSerialization); overload;
  end;

  // Test 1: Original Klasse
  TTest = class(TInterfacedObject, ITestJsonClass)
  private
    FTest : String;
    FTest2 : Integer;
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    property Test : String read GetTest write FTest;
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 2: Mit JsonSerialize(Public) Attribut
  [JsonSerialize(TJsonMemberSerialization.Public)]
  TTestWithAttribute = class(TInterfacedObject, ITestJsonClass)
  private
    FTest : String;
    FTest2 : Integer;
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    property Test : String read GetTest write FTest;
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 3: Mit JsonSerialize(Fields) Attribut
  [JsonSerialize(TJsonMemberSerialization.Fields)]
  TTestWithFields = class(TInterfacedObject, ITestJsonClass)
  private
    FTest : String;
    FTest2 : Integer;
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    property Test : String read GetTest write FTest;
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 4: Mit JsonIn auf Fields
  TTestWithJsonIn = class(TInterfacedObject, ITestJsonClass)
  private
    [JsonIn]
    FTest : String;
    [JsonIn]
    FTest2 : Integer;
    [JsonIn]
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    property Test : String read GetTest write FTest;
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 5: Mit JsonIn auf Properties
  TTestWithJsonInProps = class(TInterfacedObject, ITestJsonClass)
  private
    FTest : String;
    FTest2 : Integer;
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    [JsonIn]
    property Test : String read GetTest write FTest;
    [JsonIn]
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 6: Mit NUR JsonName auf Fields
  TTestWithOnlyJsonName = class(TInterfacedObject, ITestJsonClass)
  private
    [JsonName('Test')]
    FTest : String;
    [JsonName('Test2')]
    FTest2 : Integer;
    [JsonName('Test3')]
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    property Test : String read GetTest write FTest;
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 7: Mit JsonIn + JsonName auf Fields
  TTestWithJsonNamedFields = class(TInterfacedObject, ITestJsonClass)
  private
    [JsonIn, JsonName('Test')]
    FTest : String;
    [JsonIn, JsonName('Test2')]
    FTest2 : Integer;
    [JsonIn, JsonName('Test3')]
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    property Test : String read GetTest write FTest;
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 8: Mit TJsonMemberSerialization.In und JsonIn überall
  [JsonSerialize(TJsonMemberSerialization.In)]
  TTestWithSerializeIn = class(TInterfacedObject, ITestJsonClass)
  private
    [JsonIn]
    FTest : String;
    [JsonIn]
    FTest2 : Integer;
    [JsonIn]
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    [JsonIn]
    property Test : String read GetTest write FTest;
    [JsonIn]
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 9: Mit JsonIgnore auf Properties, nur Fields
  TTestWithIgnoredProps = class(TInterfacedObject, ITestJsonClass)
  private
    [JsonIn]
    FTest : String;
    [JsonIn]
    FTest2 : Integer;
    [JsonIn]
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    [JsonIgnore]
    property Test : String read GetTest write FTest;
    [JsonIgnore]
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 10: Custom Boolean Converter auf Field-Ebene
  [JsonSerialize(TJsonMemberSerialization.Fields)]
  TTestWithCustomConverter = class(TInterfacedObject, ITestJsonClass)
  private
    FTest : String;
    FTest2 : Integer;
    [JsonConverter(TCustomBooleanConverter)]
    FTest3 : Boolean;
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    property Test : String read GetTest write FTest;
    property Test2 : Integer read GetTest2 write FTest2;
  end;

  // Test 11: NICHT-KONFORME Feldnamen ohne führendes "F" für JSON-Mapping-Test
  // WARNUNG: Diese Klasse verwendet BEWUSST nicht-konforme Feldnamen!
  // Normalerweise sollten private Felder mit "F" beginnen (z.B. FTest)
  // Hier wird das "F" weggelassen um zu testen, ob TJsonSerializer
  // die JSON-Property-Namen direkt mit Feldnamen matchen kann
  TTestWithNonConformFieldNames = class(TInterfacedObject, ITestJsonClass)
  private
    Test : String; // NICHT-KONFORM: Sollte normalerweise "FTest" heißen
    Test2 : Integer; // NICHT-KONFORM: Sollte normalerweise "FTest2" heißen
    Test3 : Boolean; // NICHT-KONFORM: Sollte normalerweise "FTest3" heißen
  public
    constructor Create(); overload;
    constructor Create(const bTest3: Boolean); overload;
    function GetTest() : String;
    function GetTest2() : Integer;
    function GetTest3() : Boolean;
    function GetInfoText() : String;
    // Properties mit Unterstrich da Feldnamen bereits "Test", "Test2", "Test3" sind
    property Test_ : String read Test write Test;
    property Test2_ : Integer read Test2 write Test2;
  end;

  // Test Alt 1: Mit RTTI-Direktive für private Fields (AUSKOMMENTIERT)
  (*
  {$RTTI EXPLICIT FIELDS([vcPrivate, vcProtected, vcPublic, vcPublished])}
  [JsonSerialize(TJsonMemberSerialization.Fields)]
  TTestWithRTTIFields = class
  private
    FTest  : String;
    FTest2 : Integer;
    FTest3 : Boolean;
  public
    constructor Create(const bTest3: Boolean);
    function GetTest3() : Boolean;
    property Test  : String  read FTest  write FTest;
    property Test2 : Integer read FTest2 write FTest2;
  end;
  {$RTTI EXPLICIT FIELDS(DefaultFieldRttiVisibility)}
  *)


  // Test Alt 2: Mit $M+ und JsonSerialize Fields (AUSKOMMENTIERT)
  (*
  {$M+}
  [JsonSerialize(TJsonMemberSerialization.Fields)]
  TTestWithTypeInfo = class
  private
    FTest  : String;
    FTest2 : Integer;
    FTest3 : Boolean;
  public
    constructor Create(const bTest3: Boolean);
    function GetTest3() : Boolean;
    property Test  : String  read FTest  write FTest;
    property Test2 : Integer read FTest2 write FTest2;
  end;
  {$M-}
  *)


  // Performance Test Wrapper
  TJsonPerformanceTest = class
  private
    FJsonString : string;
    FIterations : Integer;
  public
    constructor Create();
    procedure TestRESTJson(var Results: TStringList);
    procedure TestTJsonSerializerMain<T: class, constructor>(var Results: TStringList);
    procedure TestTJsonSerializerWithResolverMain<T: class, constructor>(var Results: TStringList);
    procedure TestTJsonSerializerWithSmartResolverMain<T: class, constructor>(var Results: TStringList);
  end;


implementation

uses
  //SimpleJsonSerializer,
  System.JSON.Converters;

{ TTest }

constructor TTest.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTest.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTest.GetTest() : String;
begin
  Result := FTest;
end;

function TTest.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTest.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTest.GetInfoText() : String;
begin
  Result := 'TJsonSerializer Original';
end;

{ TTestWithAttribute }

constructor TTestWithAttribute.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithAttribute.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithAttribute.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithAttribute.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithAttribute.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithAttribute.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit JsonSerialize(Public) Attribut';
end;

{ TTestWithFields }

constructor TTestWithFields.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithFields.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithFields.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithFields.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithFields.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithFields.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit JsonSerialize(Fields) Attribut';
end;

{ TTestWithJsonIn }

constructor TTestWithJsonIn.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithJsonIn.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithJsonIn.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithJsonIn.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithJsonIn.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithJsonIn.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit JsonIn auf Fields';
end;

{ TTestWithJsonInProps }

constructor TTestWithJsonInProps.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithJsonInProps.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithJsonInProps.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithJsonInProps.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithJsonInProps.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithJsonInProps.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit JsonIn auf Properties';
end;

{ TTestWithOnlyJsonName }

constructor TTestWithOnlyJsonName.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithOnlyJsonName.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithOnlyJsonName.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithOnlyJsonName.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithOnlyJsonName.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithOnlyJsonName.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit nur JsonName auf Fields';
end;

{ TTestWithJsonNamedFields }

constructor TTestWithJsonNamedFields.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithJsonNamedFields.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithJsonNamedFields.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithJsonNamedFields.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithJsonNamedFields.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithJsonNamedFields.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit JsonIn+JsonName auf Fields';
end;

{ TTestWithSerializeIn }

constructor TTestWithSerializeIn.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithSerializeIn.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithSerializeIn.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithSerializeIn.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithSerializeIn.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithSerializeIn.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit Serialize In';
end;

{ TTestWithIgnoredProps }

constructor TTestWithIgnoredProps.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithIgnoredProps.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithIgnoredProps.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithIgnoredProps.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithIgnoredProps.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithIgnoredProps.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit JsonIgnore Properties';
end;

{ TTestWithCustomConverter }

constructor TTestWithCustomConverter.Create();
begin
  inherited Create();
  FTest3 := False;
end;

constructor TTestWithCustomConverter.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithCustomConverter.GetTest() : String;
begin
  Result := FTest;
end;

function TTestWithCustomConverter.GetTest2() : Integer;
begin
  Result := FTest2;
end;

function TTestWithCustomConverter.GetTest3() : Boolean;
begin
  Result := FTest3;
end;

function TTestWithCustomConverter.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit Custom Boolean Converter';
end;

{ TTestWithNonConformFieldNames }

constructor TTestWithNonConformFieldNames.Create();
begin
  inherited Create();
  Test3 := False;
end;

constructor TTestWithNonConformFieldNames.Create(const bTest3: Boolean);
begin
  inherited Create();
  Test3 := bTest3;
end;

function TTestWithNonConformFieldNames.GetTest() : String;
begin
  Result := Test;
end;

function TTestWithNonConformFieldNames.GetTest2() : Integer;
begin
  Result := Test2;
end;

function TTestWithNonConformFieldNames.GetTest3() : Boolean;
begin
  Result := Test3;
end;

function TTestWithNonConformFieldNames.GetInfoText() : String;
begin
  Result := 'TJsonSerializer mit nicht-konformen Feldnamen (ohne F-Prefix)';
end;

{ Alternative Test Implementierungen - AUSKOMMENTIERT }

{ TTestWithRTTIFields - Test Alt 1 }
(*
constructor TTestWithRTTIFields.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithRTTIFields.GetTest3() : Boolean;
begin
  Result := FTest3;
end;
*)


{ TTestWithTypeInfo - Test Alt 2 }
(*
constructor TTestWithTypeInfo.Create(const bTest3: Boolean);
begin
  inherited Create();
  FTest3 := bTest3;
end;

function TTestWithTypeInfo.GetTest3() : Boolean;
begin
  Result := FTest3;
end;
*)


{ TCustomBooleanConverter }

function TCustomBooleanConverter.CanConvert(ATypeInf: PTypeInfo) : Boolean;
begin
  Result := ATypeInf = TypeInfo(Boolean);
end;

function TCustomBooleanConverter.ReadJson(const AReader: TJsonReader; ATypeInf: PTypeInfo;
  const AExistingValue: TValue; const ASerializer: TJsonSerializer) : TValue;
begin
  if AReader.TokenType = TJsonToken.Boolean then
    Result := TValue.From<Boolean>(AReader.Value.AsBoolean)
  else if AReader.TokenType = TJsonToken.String then
    Result := TValue.From<Boolean>(SameText(AReader.Value.AsString, 'true'))
  else
    Result := TValue.From<Boolean>(False);
end;

procedure TCustomBooleanConverter.WriteJson(const AWriter: TJsonWriter; const AValue: TValue;
  const ASerializer: TJsonSerializer);
begin
  AWriter.WriteValue(AValue.AsBoolean);
end;

{ TDelphiFieldContractResolver }

constructor TDelphiFieldContractResolver.Create();
begin
  inherited Create(TJsonMemberSerialization.Fields);
end;

constructor TDelphiFieldContractResolver.Create(AMemberSerialization: TJsonMemberSerialization);
begin
  inherited Create(AMemberSerialization);
end;

function TDelphiFieldContractResolver.ResolvePropertyName(const AName: string): string;
begin
  // Entferne "F" Prefix von private Fields für JSON-Mapping
  // FTest ? Test, FUserName ? UserName, etc.
  if (Length(AName) > 1) and (AName[1] = 'F') and
     CharInSet(AName[2], ['A'..'Z']) then
    Result := Copy(AName, 2, Length(AName) - 1)
  else
    Result := AName;
end;

{ TJsonPerformanceTest }

constructor TJsonPerformanceTest.Create();
begin
  FJsonString := '{"Test":"Wert1","Test2":12,"Test3":true}';
  FIterations := 10000; // 10k Iterationen für Performance-Test
end;

procedure TJsonPerformanceTest.TestRESTJson(var Results: TStringList);
var
  sw : TStopwatch;
  tmp : TTest;
  tmp2 : TTest;
  i : Integer;
  timeSpan : TTimeSpan;
begin
  tmp2 := TTest.Create();
  try
    Results.Add('=== REST.Json ' + tmp2.GetInfoText() + ' ===');

    sw := TStopwatch.StartNew();
    for i := 1 to FIterations do
    begin
      tmp := TJson.JsonToObject<TTest>(FJsonString);
      try
        // Verifikation
        if (i = 1) then
        begin
          Results.Add('Deserialisiert - Test: "' + tmp.Test + '", Test2: ' + IntToStr(tmp.Test2) + ', Test3: ' + BoolToStr(tmp.GetTest3(), True));
          Results.Add('Rueck-Serialisiert - Test: "' + TJson.ObjectToJsonString(tmp) + '"');
        end;
      finally
        tmp.Free();
      end;
    end;
    sw.Stop();

    timeSpan := sw.Elapsed;
    Results.Add('REST.Json ' + tmp2.GetInfoText() + ' Zeit: ' + FormatFloat('0.000', timeSpan.TotalMilliseconds) + ' ms');
    Results.Add('');
  finally
    tmp2.Free();
  end;
end;

procedure TJsonPerformanceTest.TestTJsonSerializerMain<T>(var Results: TStringList);
var
  sw : TStopwatch;
  deserializedObj : T;
  deserializedIntf : ITestJsonClass;
  baseInfoClass : T;
  intfInfoClass : ITestJsonClass;
  sInfoText : String;
  js : TJsonSerializer;
  i : Integer;
  timeSpan : TTimeSpan;
begin
  baseInfoClass := T.Create();
  try
    if (Supports(baseInfoClass, ITestJsonClass, intfInfoClass)) then
    begin
      sInfoText := intfInfoClass.GetInfoText();
    end else
    begin
      sInfoText := '<Error Class-Cast>';
    end;
    Results.Add('=== Test 1 (Generic): ' + sInfoText + ' ===');

    sw := TStopwatch.StartNew();
    for i := 1 to FIterations do
    begin
      js := TJsonSerializer.Create();
      try
        deserializedObj := js.Deserialize<T>(FJsonString);
        try
          if (Supports(deserializedObj, ITestJsonClass, deserializedIntf)) then
          begin
            // Verifikation
            if (i = 1) then
            begin
              Results.Add(
                'Deserialisiert - Test: "' + deserializedIntf.GetTest() + '", ' +
                'Test2: ' + IntToStr(deserializedIntf.GetTest2()) + ', ' +
                'Test3: ' + BoolToStr(deserializedIntf.GetTest3(), True)
              );
              Results.Add('Rueck-Serialisiert - Test: "' + js.Serialize<T>(deserializedObj) + '"');
            end;
          end;
        finally
          //deserializedObj.Free();
        end;
      finally
        js.Free();
      end;
    end;
    sw.Stop();

    timeSpan := sw.Elapsed;
    Results.Add(sInfoText + ' Zeit: ' + FormatFloat('0.000', timeSpan.TotalMilliseconds) + ' ms');
    Results.Add('');
  finally
    //baseInfoClass.Free();
  end;
end;

procedure TJsonPerformanceTest.TestTJsonSerializerWithResolverMain<T>(
  var Results: TStringList);
var
  sw : TStopwatch;
  js : TJsonSerializer;
  contractResolver : TJsonDefaultContractResolver;
  i : Integer;
  timeSpan : TTimeSpan;
  deserializedObj : T;
  deserializedIntf : ITestJsonClass;
  baseInfoClass : T;
  intfInfoClass : ITestJsonClass;
  sInfoText : String;
begin
  baseInfoClass := T.Create();
  try
    if (Supports(baseInfoClass, ITestJsonClass, intfInfoClass)) then
    begin
      sInfoText := intfInfoClass.GetInfoText();
    end else
    begin
      sInfoText := '<Error Class-Cast>';
    end;
    Results.Add('=== Test 2 (Generic): ' + sInfoText + ' ===');

    sw := TStopwatch.StartNew();
    for i := 1 to FIterations do
    begin
      js := TJsonSerializer.Create();
      try
        contractResolver := TJsonDefaultContractResolver.Create(TJsonMemberSerialization.Public);
        js.ContractResolver := contractResolver;

        deserializedObj := js.Deserialize<T>(FJsonString);
        try
          if (Supports(deserializedObj, ITestJsonClass, deserializedIntf)) then
          begin
            // Verifikation
            if (i = 1) then
            begin
              Results.Add(
                'Deserialisiert - Test: "' + deserializedIntf.GetTest() + '", ' +
                'Test2: ' + IntToStr(deserializedIntf.GetTest2()) + ', ' +
                'Test3: ' + BoolToStr(deserializedIntf.GetTest3(), True)
              );
              Results.Add('Rueck-Serialisiert - Test: "' + js.Serialize<T>(deserializedObj) + '"');
            end;
          end;
        finally
          //deserializedObj.Free();
        end;
      finally
        js.Free();
      end;
    end;
    sw.Stop();

    timeSpan := sw.Elapsed;
    Results.Add(sInfoText + ' Zeit: ' + FormatFloat('0.000', timeSpan.TotalMilliseconds) + ' ms');
    Results.Add('');
  finally
    //baseInfoClass.Free();
  end;
end;

procedure TJsonPerformanceTest.TestTJsonSerializerWithSmartResolverMain<T>(
  var Results: TStringList);
var
  sw : TStopwatch;
  js : TJsonSerializer;
  smartResolver : TDelphiFieldContractResolver;
  i : Integer;
  timeSpan : TTimeSpan;
  deserializedObj : T;
  deserializedIntf : ITestJsonClass;
  baseInfoClass : T;
  intfInfoClass : ITestJsonClass;
  sInfoText : String;
begin
  baseInfoClass := T.Create();
  try
    if (Supports(baseInfoClass, ITestJsonClass, intfInfoClass)) then
    begin
      sInfoText := intfInfoClass.GetInfoText();
    end else
    begin
      sInfoText := '<Error Class-Cast>';
    end;
    Results.Add('=== Test 3 (Smart Resolver): ' + sInfoText + ' ===');

    sw := TStopwatch.StartNew();
    for i := 1 to FIterations do
    begin
      js := TJsonSerializer.Create();
      try
        smartResolver := TDelphiFieldContractResolver.Create(TJsonMemberSerialization.Fields);
        js.ContractResolver := smartResolver;

        deserializedObj := js.Deserialize<T>(FJsonString);
        try
          if (Supports(deserializedObj, ITestJsonClass, deserializedIntf)) then
          begin
            // Verifikation
            if (i = 1) then
            begin
              Results.Add(
                'Deserialisiert - Test: "' + deserializedIntf.GetTest() + '", ' +
                'Test2: ' + IntToStr(deserializedIntf.GetTest2()) + ', ' +
                'Test3: ' + BoolToStr(deserializedIntf.GetTest3(), True)
              );
              Results.Add('Rueck-Serialisiert - Test: "' + js.Serialize<T>(deserializedObj) + '"');
            end;
          end;
        finally
          //deserializedObj.Free();
        end;
      finally
        js.Free();
      end;
    end;
    sw.Stop();

    timeSpan := sw.Elapsed;
    Results.Add(sInfoText + ' Zeit: ' + FormatFloat('0.000', timeSpan.TotalMilliseconds) + ' ms');
    Results.Add('');
  finally
    //baseInfoClass.Free();
  end;
end;

// Haupttest-Procedure
procedure RunAllTests();
var
  Test : TJsonPerformanceTest;
  Results : TStringList;
begin
  Test := TJsonPerformanceTest.Create();
  Results := TStringList.Create();
  try
    Results.Add('JSON Serialization Performance Test - GEORDNET');
    Results.Add('=====================================================');
    Results.Add('Test JSON: {"Test":"Wert1","Test2":12,"Test3":true}');
    Results.Add('Iterationen: 10.000');
    Results.Add('');
    Results.Add('REFERENZ:');
    Results.Add('');

    Test.TestRESTJson(Results);

    Results.Add('TESTS IN REIHENFOLGE:');
    Results.Add('');

    Test.TestTJsonSerializerMain<TTest>(Results);
    Test.TestTJsonSerializerMain<TTestWithAttribute>(Results);
    Test.TestTJsonSerializerMain<TTestWithFields>(Results);
    Test.TestTJsonSerializerMain<TTestWithJsonIn>(Results);
    Test.TestTJsonSerializerMain<TTestWithJsonInProps>(Results);
    Test.TestTJsonSerializerMain<TTestWithOnlyJsonName>(Results);
    Test.TestTJsonSerializerMain<TTestWithJsonNamedFields>(Results);
    Test.TestTJsonSerializerMain<TTestWithSerializeIn>(Results);
    Test.TestTJsonSerializerMain<TTestWithIgnoredProps>(Results);
    Test.TestTJsonSerializerMain<TTestWithCustomConverter>(Results);
    Test.TestTJsonSerializerMain<TTestWithNonConformFieldNames>(Results);

    Test.TestTJsonSerializerWithResolverMain<TTest>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithAttribute>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithFields>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithJsonIn>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithJsonInProps>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithOnlyJsonName>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithJsonNamedFields>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithSerializeIn>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithIgnoredProps>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithCustomConverter>(Results);
    Test.TestTJsonSerializerWithResolverMain<TTestWithNonConformFieldNames>(Results);

    Test.TestTJsonSerializerWithSmartResolverMain<TTest>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithAttribute>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithFields>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithJsonIn>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithJsonInProps>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithOnlyJsonName>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithJsonNamedFields>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithSerializeIn>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithIgnoredProps>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithCustomConverter>(Results);
    Test.TestTJsonSerializerWithSmartResolverMain<TTestWithNonConformFieldNames>(Results);

    //Test.TestTJsonSerializerMain<TTestWithRTTIFields>(Results);
    //Test.TestTJsonSerializerMain<TTestWithTypeInfo>(Results);

    //FinalTest(Results);

    // Ergebnisse ausgeben
    Results.SaveToFile('JsonPerformanceTestGeordnet.txt');

  finally
    Results.Free();
    Test.Free();
  end;
end;

(*
Procedure FinalTest(var Results : TStringList);
var
  js  : TFastJsonSerializer;
  test : TTest;
  sRef : String;
const
  TESTTEXT = '{"Test":"Wert1","Test2":12,"Test3":true}';
begin
  js := TFastJsonSerializer.Create();
  try
    test := js.Deserialize<TTest>(TESTTEXT);
    sRef := js.Serialize<TTest>(test);
    Results.Add('Neuer Text: ' + sRef);
  finally
    js.Free();
  end;
end;
*)


end.
Am Ende hatte ich dann die Version mit dem Resolver als eigene Klasse / Unit SimpleJsonSerializer noch eingebaut und hier getestet.
Das ist für das Nachvollziehen aber irrelevant.
Jetzt wäre die Frage, ob das von Embarcadero so gewollt ist. Sinnvoll wäre das meiner Meinung nach aber nicht.
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe
Online

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.773 Beiträge
 
Delphi 12 Athens
 
#12

AW: Erfahrungen mit TJsonSerializer

  Alt 8. Aug 2025, 16:18
Nur so als Hinweis: Code der - und insbesondere ganze Units die - nicht auf eine Bildschirmseite passen, sollten besser als Anhang beigelegt werden.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
fisipjm

Registriert seit: 28. Okt 2013
350 Beiträge
 
Delphi 12 Athens
 
#13

AW: Erfahrungen mit TJsonSerializer

  Alt 8. Aug 2025, 21:15

Wenn es dir um Performance geht, kann ich dir das hier empfehlen:
https://github.com/paolo-rossi/delphi-neon
Ja es gibt etliche Drittanbieter-Lösungen. Darauf möchte ich aber in diesem Fall verzichten.
Der minimale Performance-Gewinn ist es mir nicht wert mich da ggf. abhängig zu machen. Ggf. regelmäßige Updates einzupflegen. Oder gar Gefahr zu laufen, dass das Projekt eingestampft wird und alles nochmal umbauen zu müssen.
Incocnito
Ich verstehe deine Grundsätzlichen Bedenken. Die sind in diesem Fall aber unbegründet. Neon ist open Source und läuft unter apache 2.0 Lizenz, bedeutet privat und Gewerblich, verwend- anpass- und verteilbar. Erstell dir einen Fork und du bist auf der sicheren Seite.
Die Zum teil 10 fache Geschwindigkeit würde ich jetzt nicht unbedingt als "minimal" bezeichnen. Alles von dir angesprochene lässt sich super über die mitzugebende Konfiguration einstellen.
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


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 11:14 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