ENG Карта сайта Контакты Главная
E-mail Рассылка
Будьте в курсе новостей от Clever Components.

Ваше имя:
E-mail:
 
ПОДПИСАТЬСЯ
 
Предыдущие Рассылки
 




Продукция Статьи Загрузки Купить Поддержка
Customer Portal   

JSON object serializer for Delphi

Delphi-Object<->Json

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 3GNU 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.

Object type declaration

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;

Serializing an instance of data type to JSON

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);

Serializing of empty string values

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;

Deserializing an instance of data type from JSON

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;

Deserializing of inherited objects

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;

Supported compiler versions

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 source code

Download Json Serializer

The library is distributed under the terms of the GNU Lesser General Public License version 3GNU General Public License

Sergey Shirokov
Clever Components team
www.clevercomponents.com

    Copyright © 2000-2017