JSON support in Delphi2010, a simple example
CodeGear, Delphi 2010, ITDevCon2009, Programming, Uncategorized Add commentsDuring last ITDevCon in Verona (ITALY) I talked in a session with title “Marshal and UnMarshal in Delphi 2010″ (we have published some photos about this great conference here).
In the first part of the session I’ve talked about JSON and many attendees were very interested in JSON and his application in everyday programming. I’m a real JSON fan so I decided to write this post about JSON support in Delphi2010. In my session I talked about serialization and deserialization, in this post I’ll show an example of code to do some JSON generation.
-
program JsonTypes;
-
{$APPTYPE CONSOLE}
-
uses
-
SysUtils,
-
IOUtils,
-
DBXJSON;
-
var
-
Obj, RestoredObject, JSON: TJSONObject;
-
arr: TJSONArray;
-
begin
-
json := TJSONObject.Create;
-
try
-
WriteLn('Empty JSON Object: ' + sLineBreak,json.ToString);
-
json.AddPair('FirstName', TJSONString.Create('Daniele'));
-
WriteLn('Simple JSON Object with property: ' + sLineBreak, json.ToString);
-
json.AddPair(TJSONPair.Create('LastName', 'Teti'));
-
WriteLn('Simple JSON Object with 2 property: ' + sLineBreak, json.ToString);
-
arr := TJSONArray.Create;
-
arr.Add(9871238712);
-
arr.Add('peter.parker@bittime.it');
-
arr.Add('Via Roma, 12');
-
json.AddPair(TJSONPair.Create('Contacts', arr));
-
WriteLn('JSON Object with a property array: ' + sLineBreak, json.ToString);
-
obj := TJSONObject.Create;
-
obj.AddPair(TJSONPair.Create('John','Doe'));
-
json.AddPair('MyUndefinedPersonObject', obj);
-
WriteLn('JSON Object with a nested Object: ' + sLineBreak,json.ToString);
-
Write('Writing JSON object to file [jsonfile]…');
-
TFile.WriteAllText('jsonfile',json.ToString);
-
WriteLn('DONE!');
-
RestoredObject := TJSONObject.ParseJSONValue(
-
TEncoding.ASCII.GetBytes(TFile.ReadAllText('jsonfile')),0
-
) as TJSONObject;
-
WriteLn('Readed JSON object from file: ' + sLineBreak, RestoredObject.ToString);
-
finally
-
json.Free; //Every contained object is automatically freed
-
end;
-
readln; //If you want to see the output while in Delphi IDE
-
end.
JSON is a lightweight data-interchange format and in Delphi 2010 you have full support for it with the built-in DBXJSON unit.
Enjoy!

November 27th, 2009 at 4:35 pm
Same sample with another json parser: “superobject”
it is a smallest and readable, and there is no need to free anything.
program JsonTypes;
{$APPTYPE CONSOLE}
uses
SysUtils,
IOUtils,
superobject;
var
Obj, RestoredObject, JSON: ISuperObject;
arr: ISuperObject;
begin
json := TSuperObject.Create;
WriteLn(’Empty JSON Object: ‘ + sLineBreak,json.AsString);
json.S['FirstName'] := ‘Daniele’;
WriteLn(’Simple JSON Object with property: ‘ + sLineBreak, json.AsString);
json.S['LastName'] := ‘Teti’;
WriteLn(’Simple JSON Object with 2 property: ‘ + sLineBreak, json.AsString);
json['Contacts'] := SA([9871238712, 'peter.parker@bittime.it', 'Via Roma, 12']);
WriteLn(’JSON Object with a property array: ‘ + sLineBreak, json.AsString);
json['MyUndefinedPersonObject'] := SO(['John', 'Doe']);
WriteLn(’JSON Object with a nested Object: ‘ + sLineBreak,json.AsString);
Write(’Writing JSON object to file [jsonfile]…’);
TFile.WriteAllText(’jsonfile’,json.AsString);
WriteLn(’DONE!’);
RestoredObject := SO(TFile.ReadAllText(’jsonfile’));
WriteLn(’Readed JSON object from file: ‘ + sLineBreak, RestoredObject.AsString);
readln; //If you want to see the output while in Delphi IDE
end.
November 27th, 2009 at 4:50 pm
and this is an example of marshalling using generics and rtti
program JsonTypes;
{$APPTYPE CONSOLE}
uses
superobject;
type
TData = record
LastName: string;
FirstName: string;
Contacts: array[0..1] of string;
end;
var
data: TData;
begin
with TSuperRttiContext.Create do
begin
data := AsType(SO(’{”LastName”: “Teti”, “FirstName”: “Daniele”, “Contacts”: ["henri", "cantu"]}’));
writeln(AsJson(data).AsString);
Free;
end;
readln;
end.
November 27th, 2009 at 4:53 pm
unfortunally the comment filter have removed the generic separator :/
{$APPTYPE CONSOLE}
uses
superobject;
type
TData = record
LastName: string;
FirstName: string;
Contacts: array[0..1] of string;
end;
var
data: TData;
begin
with TSuperRttiContext.Create do
begin
data := AsType?TData?(SO(’{”LastName”: “Teti”, “FirstName”: “Daniele”, “Contacts”: ["henri", "cantu"]}’));
writeln(AsJson?TData?(data).AsString);
Free;
end;
readln;
end.
November 27th, 2009 at 5:02 pm
@Henri:
Sure, your parser (superobject) is really great. I’m actually use it in my old D2007 projects. Should be nice a speed comparison between your parser and D2010 one. Have you already done a speed comparison?
November 27th, 2009 at 6:09 pm
yes, I just do it and this is the result:
superobject:
set: 1031
get: 906
tostring: 1125
parse: 1719
free: 281
DBX JSON:
set: 1359
get: DBX JSON can’t find property by name :/
tostring: 1079
parse: 3453
free: 390
AFAIK, the DBX Json parser is not able to index properties, and superobject use an auto-balanced avl tree.
program Project43;
{$APPTYPE CONSOLE}
uses
Windows,
SysUtils,
dbxjson,
superobject;
var
i: Integer;
obj1, obj3: ISuperObject;
obj2, obj4: TJSONObject;
c: Cardinal;
str: string;
begin
writeln(’superobject:’);
c := GetTickCount;
obj1 := TSuperObject.Create(stObject);
for i := 1 to 1000000 do
obj1.AsObject.I[inttostr(i)] := I;
writeln(’set: ‘, GetTickCount - c);
c := GetTickCount;
for i := 1 to 1000000 do
obj1.AsObject.I[inttostr(i)];
writeln(’get: ‘, GetTickCount - c);
c := GetTickCount;
str := obj1.AsString;
writeln(’tostring: ‘, GetTickCount - c);
c := GetTickCount;
obj3 := SO(str);
writeln(’parse: ‘, GetTickCount - c);
str := ”;
c := GetTickCount;
obj1 := nil;
writeln(’free: ‘, GetTickCount - c);
writeln(’DBX JSON:’);
c := GetTickCount;
obj2 := TJSONObject.Create;
for i := 1 to 1000000 do
obj2.AddPair(TJSONPair.Create(inttostr(i), TJSONNumber.Create(i)));
writeln(’set: ‘, GetTickCount - c);
writeln(’get: ‘, ‘DBX JSON can”t find property by name :/’);
c := GetTickCount;
str := obj2.ToString;
writeln(’tostring: ‘, GetTickCount - c);
c := GetTickCount;
obj4 := TJSONObject.ParseJSONValue(TEncoding.ASCII.GetBytes(str), 0) as TJSONObject;
writeln(’parse: ‘, GetTickCount - c);
c := GetTickCount;
obj2.Free;
writeln(’free: ‘, GetTickCount - c);
readln;
end.
November 27th, 2009 at 6:19 pm
I’ve a question about superobject.
Can superobject use Converter and Reverter while serialize/unserialize? (like what I’ve used here http://www.danieleteti.it/?p=146)
November 27th, 2009 at 6:55 pm
yes, using the current SVN version, there 2 defaults serialisers for boolean et TDateTime, take a look on source code in the TSuperRTTIContext class.
November 30th, 2009 at 5:30 pm
JSON objects used in DBX have a different requirement base than SO. They are mainly intended to support and enhance the data serialization layer present in DBX.
It is a lightweight cross-platform code that needs to work with non-Delphi clients based on single source code base.
I think it is important to learn how to use it if you intend to work with the low-level DBX communication API.
Regards,
Adrian Andrei
http://www.embarcadero.com
December 2nd, 2009 at 12:39 pm
[Daniele] this post should interest you:
http://www.progdigy.com/forums/viewtopic.php?p=15535
[Adrian]
I noticed that the dbxjson parser can only read the json producted by itself because no spaces are allowed.
I think you should improve the parser according to the RFC: http://www.ietf.org/rfc/rfc4627.txt.
Most of json parsers also ignore comments // and /* */.
Regards
December 3rd, 2009 at 10:28 am
Why should we have to use a limited JSON parser for DBX? It would be a lot better if we could decide what parser to use, and go with that. I really like the SuperObject implementation, only thing missing there now is attribute support for the RTTI part. The only thing I don’t like about SuperObject is the name “SuperObject”
It should have been just JSON (or something like SimpleJSON).
It would be great if Embarcadero would work more with the community in the next versions. Instead of creating their own versions of things that already are made, they could try to integrate them and concentrate on the stuff third party developers have no way of implementing. Just look how good the MM became when they included FastMM…
And they should open up VCL!! In these days it should be in a SVN repository that all Software Assurance customers have access to, and easy to compile. The license could be the same (for the package part, new compiled packages could have a different name than release packages, but be available to those who want to use those instead).
January 19th, 2010 at 5:14 pm
Henri, Daniele, thanks for pointing out for me the RFC. I used as reference the JSON.ORG site and grammar. It will not be a problem to add the white spaces in.
I appreciate your feedback,
AA
February 12th, 2010 at 7:26 pm
Daniele, Is possible to convert an instance like a TForm object from Server to Client side using JSON? My idea is to create a Client Application, like a web browser, that will receive “TForm objects” from the Server Side, when the user make a request on the Client Side. Could you give me some example. Thank you!
February 13th, 2010 at 12:05 pm
@Bruno
While is possible serialize a TForm object (as every other object) is not possibile restore that “JSON form” in a instance of the original form, becouse you MUST have that declaration available in the client side.
For a “brower” like software, probably you could download a package containing the form and then create it in the client. So you can use datasnap (REST support?) to talk with the application server.
My 2 Cent
March 4th, 2010 at 6:36 pm
[...] … Mail (will not be published) (required) Website. secureSWF Blog is proudly powered by …while true do; Blog Archive JSON support in Delphi2010, a …data := AsType?TData?(SO(’{LastName: Teti, FirstName: Daniele, Contacts … [...]
April 1st, 2010 at 7:58 pm
@Daniele:
You do not have to have the form’s declaration available in the client side to display the form. I was doing this back in D2/BCB1, using the Delphi stream format .DFM and storing the forms in a database.
You won’t be able to access the components by their variable/field name in Delphi. But you can use the Components array to iterate through them to find the components you’re looking for.
You MUST register any component classes that will be stored in the form so the form can recreated in the client. At least, this is how the .DFM streaming mechanism works. When you have a component declared in the form’s class, Delphi does this for you. If you don’t have a class declaration available, you have to call RegisterClasses by hand.
It may be that the JSON & SimpleObject marshaling features do not support this. But the TReader and TWriter components do. This is one case where I wish the JSON support added by Embarcadero was better integrated into the existing TPersistent streaming engine.
April 3rd, 2010 at 9:19 am
@Jon
Sure, I’m agee with you, you can read the “DFM” resources without the original class, but is only the “visual” part anche not the “Code” part. So you still need to have the declarationa available in the client side if you whant a real instance of the form and not only the visual aspect.
April 20th, 2010 at 2:17 pm
oh thanks
April 21st, 2010 at 12:22 pm
очаровательно!…
нет автомобильным In the first part of the session I’ve talked about JSON and many attendees were very interested in JSON and his application in everyday programming. I’m…
May 4th, 2010 at 2:15 am
Браво, вас посетила просто блестящая мысль…
In the first part of the session I’ve talked about JSON and many attendees were very interested in JSON and his application in everyday programming. I’m a […..
June 23rd, 2010 at 4:09 am
Is it possible to transmit a TMemoryStream?
June 23rd, 2010 at 8:39 am
Yes, but must be encoded in some TEXTUAL encoding. You can use, for example, BASE64 encoding. I’m already done similar thing with XML and JSON as well.
August 18th, 2010 at 7:47 pm
Sorry , Daniele
But show an example ?