Home > Blockchain >  How to dynamically ignore property when I'm Serialization object to json using TJson.ObjectToJs
How to dynamically ignore property when I'm Serialization object to json using TJson.ObjectToJs

Time:04-06

I have this class:

unit untPerson;
interface
type TPerson = class
  private
    fName  : string;
    fEmail : string;
    fAge   : integer;
  published 
    property Name  : string  read fName  write fName;
    property Email : string  read fEmail write fEmail;
    property Age   : integer read fAge   write fAge;
end;
implementation
end.

And i need to serialize to Json using this code

TJson.ObjectToJsonString(objPerson, []);

But i need to skip Age if equal 0.

if objPerson.Age = 0 then
  result := '{"name":"Lucas", "email":"[email protected]"}'
else
  result := '{"name":"Lucas", "email":"[email protected]", "age":30}';

How Can I Do?

if objPerson.Age = 0 then
  result := '{"name":"Lucas", "email":"[email protected]"}'
else
  result := '{"name":"Lucas", "email":"[email protected]", "age":30}';

CodePudding user response:

You can't dynamically ignore properties by using code: TJson.ObjectToJsonString(objPerson, []);. You can put empty string by custom TJSONInterceptor, like Remy Lebeau says in comments(https://en.delphipraxis.net/topic/6155-tjson-suppressemptyvalues-for-empty-integer-double-and-class-fields/), but to exclude it from json you need to put option joIgnoreEmptyStrings: TJson.ObjectToJsonString(objPerson, [joIgnoreEmptyStrings]);.

One more way to do it: use custom converter (descendant of TJsonConverter), but problem is that you can’t use TJson.ObjectToJsonString in this case, because it have precompiled code with creating JSONMarshal using specifically TJSONConverter class without possibility of overriding: TJSONMarshal.Create(TJSONConverter.Create, true, CFRegConverters);. So you need to reimplement all chain of call TJSON.ObjectToJsonString -> ObjectToJsonValue -> TJSONConverters.GetJSONMarshaler -> TJSONMarshal.Create(TJSONConverter.Create, true, CFRegConverters);. And after that you must use this custom implementation.

Easiest way – to add custom method directly to class:

  TPerson = class
  private
    fName  : string;
    fEmail : string;
    fAge   : integer;
  published
    function ToJsonString : string; virtual;
    class function FromJsonString(const AJsonStr : string) : TPerson;
    property Name  : string  read fName  write fName;
    property Email : string  read fEmail write fEmail;
    property Age   : integer read fAge   write fAge;
    end;

In this case – you can use any custom logic, but the same code: TJson.ObjectToJsonString(objPerson, []);.will does not work correctly. You must use these new methods.

And last – you can try to find some other 3rd party JSON serializers.

CodePudding user response:

As an alternative solution, mORMot have this diamond, and you can always use ObjectToJson to serialize very fast any TObject in a centralized way:

program TestJson;

{$APPTYPE CONSOLE}

{$R *.res}

uses
  Syncommons, mORMot;

type TPerson = class
  private
    fName  : string;
    fEmail : string;
    fAge   : integer;
  public
    class procedure ClassWriter(const aSerializer: TJSONSerializer;
                                aValue: TObject; aOptions: TTextWriterWriteObjectOptions);
  published
    property Name  : string  read fName  write fName;
    property Email : string  read fEmail write fEmail;
    property Age   : integer read fAge   write fAge;
end;

{ TPerson }

class procedure TPerson.ClassWriter(const aSerializer: TJSONSerializer;
                                    aValue: TObject; aOptions: TTextWriterWriteObjectOptions);
var Person: TPerson absolute aValue;
begin
  if Person.Age=0 then
    aSerializer.AddJSONEscape(['Name',Person.Name,
                               'Email',Person.Email
                              ])
  else
    aSerializer.AddJSONEscape(['Name',Person.Name,
                               'Email',Person.Email,
                               'Age',Person.Age
                              ]);
end;

var Person : TPerson;
    JsonPerson : string;
begin
  TJSONSerializer.RegisterCustomSerializer(TPerson,nil,TPerson.ClassWriter);
  Person := TPerson.Create;
  try
    Person.Name := 'Jon';
    Person.Email := '[email protected]';
    Person.Age := 10;
    writeln(ObjectToJson(Person)); // Result {"Name":"Jon","Email":"[email protected]","Age":10}

    Person.Age := 0;
    writeln(ObjectToJson(Person)); // Result {"Name":"Jon","Email":"[email protected]"}
  finally
    Person.Free;
  end;
  readln;
end.

Please, find further details in the amazing documentation

  • Related