Recent

Author Topic: ezjson - JSON serialize / deserialize with attributes  (Read 187 times)

mr-highball

  • Full Member
  • ***
  • Posts: 103
ezjson - JSON serialize / deserialize with attributes
« on: January 03, 2020, 12:49:26 am »
Hey everyone, hope everyone had a good start to the new year  :D
The past few days I've been working on JSON serialization / deserialization using custom attributes. These work by attaching two types of decorators to either your classes / interfaces or to properties of classes / interfaces.
Each decorator simply takes a name to be used when when serializing

JsonObject('objectName')
JsonProperty('propertyName')

Once you have your decorated objects, you can then call one of two generic methods,
EZSerialize<T>(...) (outputs json)
EZDeSerialize<T>(...) (input json)

An example is worth a 1000 words, so here you go,

Code: Pascal  [Select]
  1.   { TTestDecorated }
  2.   (*
  3.     a simple object decorated with a custom name to be used when serializing and
  4.     deserializing, as well as some simple typed properties to include in
  5.     serialization
  6.   *)
  7.   [JsonObject('myTestObject')]
  8.   TTestDecorated = class(TObject)
  9.   private
  10.     FTest : String;
  11.     FTestInt : Integer;
  12.   published
  13.     [JsonProperty('test')]
  14.     property Test : String read FTest write FTest;
  15.  
  16.     [JsonProperty('testInteger')]
  17.     property TestInt : Integer read FTestInt write FTestInt;
  18.   end;
  19.  
  20.   ...
  21.  
  22. procedure TestSimple;  
  23. var
  24.   LTest : TTestDecorated;
  25.   LJSON,
  26.   LError : String;
  27. begin
  28.   //setting a value on our test
  29.   LTest := TTestDecorated.Create;
  30.   LTest.Test := 'a test';
  31.  
  32.   //calling serialize
  33.   if not (EZSerialize<TTestDecorated>(LTest, LJSON, LError)) then
  34.     raise Exception.Create(LError) //failed to serialize
  35.   else
  36.     WriteLn(LJSON); //success
  37. end;
  38.  

the output from above is below,
{ "myTestObject" : { "test" : "a value", "testInteger" : 0 } }

Nested object or interface properties can also be used in conjunction with standard types, here's another example (minus the calling code for brevity)

Code: Pascal  [Select]
  1. TTestComplex = class(TObject)
  2.   private
  3.     FDecorated: TTestDecorated;
  4.     FNonDecorated: TTestNonDecorated;
  5.   public
  6.     constructor Create;
  7.     destructor Destroy; override;
  8.   published
  9.     [JsonProperty('decorated')]
  10.     property Decorated : TTestDecorated read FDecorated;
  11.  
  12.     [JsonProperty('nonDecorated')]
  13.     property NonDecorated : TTestNonDecorated read FNonDecorated;
  14.   end;
  15.  

and here's the output when serialized,

{ "TestComplex" : { "decorated" : { "test" : "a value", "testInteger" : 0 }, "nonDecorated" : { "test" : "" } } }

I'm actively working on this, and right now only serialization has been implemented (still working on deserialize  :-[ ) but I thought someone might find some use or could provide a second set of eyes.

here's the repo, https://github.com/mr-highball/ezjson

Cheers 🍻
« Last Edit: January 03, 2020, 01:06:00 am by mr-highball »
-Highball