Jump to content
Sign in to follow this  
P@Sasa

TJson - SuppressEmptyValues for empty Integer, Double and Class fields?

Recommended Posts

I'm working in Delphi 10.2

I will need to make Json object which would need to ignore empty integers, numbers or entire class.

For Integers I've tried with attribute [SuppressZero] and it works OK but problem is that integer output is like string, not integer.

Is there any solution for that?

Example classes:

    TOtherClass = class
    private
        FStringField1: string;
        FIntegerField1: Integer;
        FDoubleField1: Double;
    published
        property StringField1: string read FStringField1 write FStringField1;
        property IntegerField1: Integer read FIntegerField1 write FIntegerField1;
        property DoubleField1: Integer read FDoubleField1 write FDoubleField1;
    end;

    TMainClass = class
    private
        FStringField: string;
        FIntegerField: Integer;
        FDoubleField: Double;
        FOtherClass: TOtherClass;
    published
        property StringField: string read FStringField write FStringField;
        property IntegerField: Integer read FIntegerField write FIntegerField;
        property DoubleField: Double read FDoubleField write FDoubleField;
        property OtherClass: TOtherClass read FOtherClass;
    public
    end;

If I fill all fields I'll get result like this:

{
	"StringField": "123",
	"IntegerField": 1,
	"DoubleField": 111.11,
	"OtherClass": {
		"StringField1": "999",
		"IntegerField1": 9,
		"DoubleField1": 999.99
	}
}

What I need is that if integers and doubles are 0 then it shoud not exists in result, and if entire Class is empty than that class shoud not be in result Json.

That means for: Integerfield=0, DoubleField=0.00, OtherClass->StringField1='', OtherClass->IntegerField1=0, OtherClass->doublefield1=0.00 the result shoud be:

{
	"StringField": "123",
}

not
{
	"StringField": "123",
	"IntegerField": 0,
	"DoubleField": 0.0,
	"OtherClass": {
		"StringField1": "",
		"IntegerField1": 0,
		"DoubleField1": 0.00
	}
} 
or
{
	"StringField": "123",
	"IntegerField": 0,
	"DoubleField": 0.0,
	"OtherClass": {	}
}

I've tried for "integer fields" something like Uwe Raabe did with Date fields and it works for integer values 0(zero) but for integers different from 0 problem is that the result in JSON is string not integer because StringConverter and StringReverter works with string.

My idea for class with attribute [SupressZero]

    TOtherClass = class
    private
        FStringField1: string;
        [SuppressZero]
        FIntegerField1: Integer;
        [SuppressZero]
        FDoubleField1: Double;
    published
        property StringField1: string read FStringField1 write FStringField1;
        property IntegerField1: Integer read FIntegerField1 write FIntegerField1;
        property DoubleField1: Integer read FDoubleField1 write FDoubleField1;
    end;

    TMainClass = class
    private
        FStringField: string;
        [SuppressZero]
        FIntegerField: Integer;
        [SuppressZero]
        FDoubleField: Double;
        [SuppressZero]
        FOtherClass: TOtherClass;
    published
        property StringField: string read FStringField write FStringField;
        property IntegerField: Integer read FIntegerField write FIntegerField;
        property DoubleField: Double read FDoubleField write FDoubleField;
        property OtherClass: TOtherClass read FOtherClass;
    public
    end;

My code for integer fields (did not try supressZero for Double and Class because this don't work for integer fields)

type
    SuppressZeroAttribute = class(JsonReflectAttribute)
    public
        constructor Create;
    end;

    TSuppressZeroInterceptor = class(TJSONInterceptor)
    public
        function StringConverter(Data: TObject; Field: string): string; override;
        procedure StringReverter(Data: TObject; Field: string; Arg: string); override;
    end;

implementation

{ SuppressZeroAttribute }

 constructor SuppressZeroAttribute.Create;
 begin
 inherited Create(ctString, rtString, TSuppressZeroInterceptor);
 end;

{ TSuppressZeroInterceptor }

function TSuppressZeroInterceptor.StringConverter(Data: TObject; Field: string): string;
var
    RttiContext: TRttiContext;
    iValue:integer;
begin
    iValue := RttiContext.GetType(Data.ClassType).GetField(Field).GetValue(Data).AsType<Integer>;
    if (iValue = 0) then
    begin
        Result := EmptyStr;
    end
    else
    begin
        Result := iValue.ToString;
    end;
end;

procedure TSuppressZeroInterceptor.StringReverter(Data: TObject; Field, Arg: string);
var
    RttiContext: TRttiContext;
    iValue:Integer;
begin
    if (Arg.IsEmpty) or (Arg.StartsWith('0')) or (Arg.ToLower.Contains('null')) then
    begin
        iValue := 0;
    end
    else
    begin
        iValue := arg.ToInteger;
    end;
    RttiContext.GetType(Data.ClassType).GetField(Field).SetValue(Data, iValue);
end;

If looking only string and integer fields for first class result is:

for StringField="123", IntegerField=0
{
	"StringField": "123"    -> OK - there is no IntegerField
}

for StringField="123", IntegerField=123
{
	"StringField": "123",	
	"IntegerField": "123" -> NOT OK - this shoud be without quotes ""
}

Is there some solution for "SupressEmptyValues" for integer, double and classes that can be done with JSonReflectAttribute and TJSONInterceptor or should I look for some other solution for my problem?

Thanks for replays.

 

Edited by P@Sasa

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

×