|
Here is the second edition of the JSON Serializer library from the Delphi JSON serialization using Rtti article.
The updated library is completely Open Source and distributed under the terms of the
GNU Lesser General Public License version 3, GNU General Public License
Now, you can serialize and deserialize arrays and unions of objects of different types, deserialize inherited objects, serialize empty strings and many more. The article includes both the source code of the Json Serializer classes (TclJsonSerializer) and unit-test code that demonstrates how to serialize and deserizlise differrent data types, inlcuding Delphi strings, integers, objects and arrays.
Join our Mailing List and stay tuned: SUBSCRIBE
|
TclJsonSerializer utilizes the RTTI library and custom Delphi attributes for linking user-defined Delphi objects and properties with the corresponding JSON data parts. The updated JSON serializer correctly invokes constructors of serialized objects by requesting RTTI information for object constructors and calling it with the Invoke method.
For defining a data type, you need to attach the TclJsonPropertyAttribute attribute to the property you want to serialize.
// [Delphi]
TclTestObject = class
private
FStringValue: string;
FIntegerValue: Integer;
FIntArray: TArray<Integer>;
public
[TclJsonString('stringValue')]
property StringValue: string read FStringValue write FStringValue;
[TclJsonProperty('integerValue')]
property IntegerValue: Integer read FIntegerValue write FIntegerValue;
[TclJsonProperty('intArray')]
property IntArray: TArray<Integer> read FIntArray write FIntArray;
end; |
1. Create an instance of data type.
// [Delphi]
obj := TclTestObject.Create();
obj.StringValue := 'test';
obj.IntegerValue := 123;
SetLength(intArr, 2);
obj.IntArray := intArr;
intArr[0] := 111;
intArr[1] := 222; |
2. Serialize the object to the JSON string.
// [Delphi]
json := TclJsonSerializer.ObjectToJson(obj); |
Normally, empty and default parameters aren't uncluded to JSON strings. But sometimes, software at recipient side requires an empty parameter to be inlcuded. E.g., Dropbox API requires an empty URL parameter to be present in the ListFolder requests when listing the root folder. The new TclJsonRequiredAttribute custom attribute allows you to mark the required property when declaring the object type:
// [Delphi]
TclTestObject = class
private
FRequiredStringValue: string;
public
[TclJsonRequired]
[TclJsonString('required-string-value')]
property RequiredStringValue: string read FRequiredStringValue write FRequiredStringValue;
end; |
Call to the TclJsonSerializer.JsonToObject class method and specify both the serializeble data type and the JSON-encoded source string.
// [Delphi]
obj := TclJsonSerializer.JsonToObject(TclTestObject, jsonEtalon) as TclTestObject; |
To deserialize the object instances of inherited types, you need to supply the type of the object being serialized. Usually, a special string property is declared in the basic class. Descendants fill this property with unique type identifier. The JSON serializer provides a special custom attribute for associating the type identifiers with real Delphi types: TclJsonTypeNameMapAttribute.
// [Delphi]
[TclJsonTypeNameMap('tag', 'child', 'clJsonSerializerTests.TclTestChildObject')]
[TclJsonTypeNameMap('tag', 'child2', 'clJsonSerializerTests.TclTestChild2Object')]
TclTestBaseObject = class
....
public
[TclJsonString('tag')]
property Tag: string read FTag write FTag;
end;
TclTestChildObject = class ....
TclTestChild2Object = class ....
constructor TclTestChildObject.Create;
begin
inherited Create();
Tag := 'child';
end;
constructor TclTestChild2Object.Create;
begin
inherited Create();
Tag := 'child2';
end; |
The JSON serializer uses Delphi RTTI for creating serializable objects. It is necessary to specify the unit name together with the object type within the TclJsonTypeNameMap parameters. Also, Delphi compiler always removes unreferenced types from resulting executable code. So if your data objects are not instantiated in your code, you need to reference its types or use the {$STRONGLINKTYPES ON} compiler directive. A possible solution to this problem can be seen in the How can I make sure RTTI is available for a class without instantiating it article.
The declared TclTestBaseObject type can be used in object properties, arrays and also can be serialized and deserialized as a root object:
// [Delphi]
TclTestObject = class
private
FReferenceObject: TclTestBaseObject;
FObjectArray: TArray<TclTestBaseObject>;
procedure SetReferenceObject(const Value: TclTestBaseObject);
procedure SetObjectArray(const Value: TArray<TclTestBaseObject>);
public
constructor Create;
destructor Destroy; override;
[TclJsonProperty('reference')]
property ReferenceObject: TclTestBaseObject read FReferenceObject write SetReferenceObject;
[TclJsonProperty('array')]
property ObjectArray: TArray<TclTestBaseObject> read FObjectArray write SetObjectArray;
end; |
You need to bother about deleting instances of array elements and object references in your code:
// [Delphi]
procedure TclTestObject.SetReferenceObject(const Value: TclTestBaseObject);
begin
FReferenceObject.Free();
FReferenceObject = Value;
end;
procedure TclTestObject.SetObjectArray(const Value: TArray<TclTestBaseObject>);
var obj: TObject;
begin
if (FObjectArray <> nil) then
for obj in FObjectArray do obj.Free();
FObjectArray := Value;
end;
constructor TclTestObject.Create;
begin
inherited Create();
FReferenceObject := nil;
FObjectArray := nil;
end;
destructor TclTestObject.Destroy;
begin
SetReferenceObject(nil);
SetObjectArray(nil);
inherited;
end;
|
Json Serializer can be used in RAD Studio XE3 and later. If you modify the sources and remove all references to the RAD Studio namespaces in the 'uses' sections, you can use the library in RAD Studio 2009, 2010, XE and XE2 as well.
Download on GitHub
The library is distributed under the terms of the GNU Lesser General Public License version 3, GNU General Public License
Sergey Shirokov
Clever Components team
www.clevercomponents.com
|