JSON support in Delphi2010, a simple example

CodeGear, Delphi 2010, ITDevCon2009, Programming, Uncategorized Add comments

During 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.

  1. program JsonTypes;
  2. {$APPTYPE CONSOLE}
  3. uses
  4.   SysUtils,
  5.   IOUtils,
  6.   DBXJSON;
  7. var
  8.   Obj, RestoredObject, JSON: TJSONObject;
  9.   arr: TJSONArray;
  10. begin
  11.   json := TJSONObject.Create;
  12.   try
  13.     WriteLn('Empty JSON Object: ' + sLineBreak,json.ToString);
  14.     json.AddPair('FirstName', TJSONString.Create('Daniele'));
  15.     WriteLn('Simple JSON Object with property: ' + sLineBreak, json.ToString);
  16.     json.AddPair(TJSONPair.Create('LastName', 'Teti'));
  17.     WriteLn('Simple JSON Object with 2 property: ' + sLineBreak, json.ToString);
  18.     arr := TJSONArray.Create;
  19.     arr.Add(9871238712);
  20.     arr.Add('peter.parker@bittime.it');
  21.     arr.Add('Via Roma, 12');
  22.     json.AddPair(TJSONPair.Create('Contacts', arr));
  23.     WriteLn('JSON Object with a property array: ' + sLineBreak, json.ToString);
  24.     obj := TJSONObject.Create;
  25.     obj.AddPair(TJSONPair.Create('John','Doe'));
  26.     json.AddPair('MyUndefinedPersonObject', obj);
  27.     WriteLn('JSON Object with a nested Object: ' + sLineBreak,json.ToString);
  28.     Write('Writing JSON object to file [jsonfile]…');
  29.     TFile.WriteAllText('jsonfile',json.ToString);
  30.     WriteLn('DONE!');
  31.     RestoredObject := TJSONObject.ParseJSONValue(
  32.       TEncoding.ASCII.GetBytes(TFile.ReadAllText('jsonfile')),0
  33.       ) as TJSONObject;
  34.     WriteLn('Readed JSON object from file: ' + sLineBreak, RestoredObject.ToString);
  35.   finally
  36.     json.Free;  //Every contained object is automatically freed
  37.   end;
  38.   readln; //If you want to see the output while in Delphi IDE
  39. 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!

22 Responses to “JSON support in Delphi2010, a simple example”

  1. Henri Gourvest Says:

    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.

  2. Henri Gourvest Says:

    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.

  3. Henri Gourvest Says:

    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.

  4. Daniele Teti Says:

    @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?

  5. Henri Gourvest Says:

    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.

  6. Daniele Teti Says:

    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)

  7. Henri Gourvest Says:

    yes, using the current SVN version, there 2 defaults serialisers for boolean et TDateTime, take a look on source code in the TSuperRTTIContext class.

  8. Adrian Andrei Says:

    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

  9. Henri Gourvest Says:

    [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

  10. Atle Says:

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

  11. Adrian Andrei Says:

    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

  12. Bruno Says:

    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!

  13. Daniele Teti Says:

    @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

  14. tdata Says:

    [...] … 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 … [...]

  15. JonRobertson Says:

    @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.

  16. Daniele Teti Says:

    @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.

  17. mohammad Says:

    oh thanks ;)

  18. Kylie Batt Says:

    очаровательно!…

    нет автомобильным 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…

  19. Kylie Batt Says:

    Браво, вас посетила просто блестящая мысль…

    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 […..

  20. Wagner Freitas Says:

    Is it possible to transmit a TMemoryStream?

  21. Daniele Teti Says:

    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.

  22. Wagner Freitas Says:

    Sorry , Daniele
    But show an example ?

Leave a Reply

WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS Log in