Learn How to Use the New JSON Features in RAD Studio 10 Seattle - Webinar

Wednesday, March 2, 2016

Pawel Glowacki - Embarcadero Technologies

RAD Studio 10 “Seattle” introduces many new features for working with JSON documents. In this demo-oriented session you will learn new ways of reading and generating JSON that requires less memory and provides better performance. This webinar presents new ways of working with JSON in RAD Studio 10 "Seattle"! There are better ways of writing and reading JSON. New JSON writers, fluent builders and fast readers! As a bonus I'm also going to present custom "TJSONDocument" component plus implementing handy VCL Delphi "JSON Viewer" app that I hope you will find useful in your developer work-)

Webinar Replay on YouTubehttps://www.youtube.com/watch?v=onX1MoE3mUM

Sample Source Code on CodeCentralhttp://cc.embarcadero.com/item/30490

 

Whitepaper: http://cc.embarcadero.com/Item/30496

Delphi JSON Custom Components: https://github.com/pglowack/DelphiJSONComponents

Delphi JSON Viewer (source code): https://github.com/pglowack/DelphiJSONViewer

Delphi JSON Viewer (executable): http://cc.embarcadero.com/Item/30495

 

JSON Sample included with 10 Seattle can be found at:

C:\Users\Public\Documents\Embarcadero\Studio\17.0\Samples\Object Pascal\RTL\Json

 

Information/Resource Links:

 

Reduce development time and get to market faster with RAD Studio, Delphi, or C++Builder. Design. Code. Compile. Deploy.

Start Free Trial   Free Delphi Community Edition   Free C++Builder Community Edition   Upgrade Today  

  • Pawel, Thank you for your answer. What I want to achieve is to use the DataSnap Rest server and generate JSON with TJsonTextWriter class (the second framework of your presentation). Here is the code that I initially test : It's a server method that returns a string which represents the JSON. // function TSMCustomer.GetAll1: string; var i: Integer; oCust: TDAOCustomer; oDAOCustomer: TDAOCustomers; ojsonarray: TJSONArray; ojsonobject: TJSONObject; ojsonvalue: TJSONValue; oList: TObjectList; res: TJSONObject; StringWriter: TStringWriter; Writer: TJsonTextWriter; begin oDAOCustomer := TDAOCustomers.Create('CUSTOMER','CUSTOMER_NAME',ftString); //my data access object // oList := oDAOCustomer.findAll; //This list contains all my data access objects // StringWriter := TStringWriter.Create(); Writer := TJsonTextWriter.Create(StringWriter); try Writer.WriteStartArray; for i:=0 to oList.Count-1 do begin oCust := oList.Items[i]; // Writer.WriteStartObject; Writer.WritePropertyName('customerName'); Writer.WriteValue(oCust.FCUSTOMER_NAME); Writer.WritePropertyName('isValid'); Writer.WriteValue(oCust.FIS_VALID); Writer.WriteEndObject; // end; Writer.WriteEndArray; // Result := StringWriter.ToString; finally oList.free; oDAOCustomer.Free; end; end; // As the above function returns a string I decided to modify it like this in order to return a TJSONArray: function TSMCustomer.GetAll: TJSONArray; var i: Integer; oCust: TDAOCustomer; oDAOCustomer: TDAOCustomers; oList: TObjectList; res: TJSONObject; WriterJsonObject: TJsonObjectWriter; begin oDAOCustomer := TDAOCustomers.Create('CUSTOMER','CUSTOMER_NAME',ftString); // oList := oDAOCustomer.findAll; // WriterJsonObject := TJsonObjectWriter.Create(True); try WriterJsonObject.DateFormatHandling := TJsonDateFormatHandling.Iso; WriterJsonObject.WriteStartArray; for i:=0 to oList.Count-1 do begin oCust := oList.Items[i]; // WriterJsonObject.WriteStartObject; WriterJsonObject.WritePropertyName('customerName'); WriterJsonObject.WriteValue(oCust.FCUSTOMER_NAME); WriterJsonObject.WritePropertyName('isValid'); WriterJsonObject.WriteValue(oCust.FIS_VALID); WriterJsonObject.WriteEndObject; // end; WriterJsonObject.WriteEndArray; // Result := TJSONArray(WriterJsonObject.JSON); finally oList.free; oDAOCustomer.Free; end; end; With this function it works well but I did not use the TJSONTextWriter class.
  • Rafik, Please explain what you want to achieve and what framework you are using. I thought it is RAD Server, but know I see that it is DataSnap. With DataSnap passing objects is different because DataSnap is doing a lot of serialization and de-serialization, In DataSnap it is super important to use proper argument and result types in server methods. If you return "TJSONObject" from a DataSnap method, it should serialize fine. Do you have a code sample to look at? Paweł
  • Hi Paweł, Thank you for your answer. It works well but I am still a bit confused about the method. Indeed what I understood about the new JSON features is that with the TJsonTextWriter and TJSONObjectBuilder classes we can improve the performances by not creating intermediate objects. But with the method "ParseJSONValue" we do create these intermediate objects. So what I am wondering if these new features are compatible with the DataSnap component ? PS : I also tried to use thus class TJsonObjectWriter and it works well (but we still create the intermediate objects). Rafik
  • Hi Rafik, Try passing the JSON string received from server to "">docwiki.embarcadero.com/.../System.JSON.TJSONObject.ParseJSONValue". Please let me know if it helps. Paweł
  • Hello, I read your paper called : "Learn How to Use the New JSON Features in RAD Studio 10 “Seattle" and I would like to use the new JSON features with Datasnap. But I met an issue : with the TJsonTextWriter; I only manage to produce a string and not a TJSONObject. In this cast my rest server returns a string and my client did not manage to see the result as a JSON. Do you have any advice for solving my issue ? Thank you very much.
  • Thank you so much for the explanation. I will follow your suggest.
  • Hi Fabio, It would be difficult to use builders to generate JSON in the loop. With builders there is one long concatenated call to a builder class. It cannot be easily broken into pieces. In your code after "beginArray("Employees")" cannot be a different call placed. I would suggest using "writers" or just generate JSON as a string. I have put together a simple demo. New Delphi 10 project, drag "EMPLOYEE" node from Data Explorer onto the form. I have also a memo to output the resulting JSON: uses System.JSON.Writers, System.JSON.Types; {$R *.fmx} procedure TForm2.Button1Click(Sender: TObject); var StringWriter: TStringWriter; Writer: TJsonTextWriter; begin StringWriter := TStringWriter.Create(); Writer := TJsonTextWriter.Create(StringWriter); try Writer.Formatting := TJsonFormatting.Indented; Writer.WriteStartObject; Writer.WritePropertyName('employees'); Writer.WriteStartArray; EmployeeTable.Open; try while not EmployeeTable.Eof do begin Writer.WriteStartObject; Writer.WritePropertyName('EmployeeNumber'); Writer.WriteValue(EmployeeTable.FieldByName('EMP_NO').AsInteger); Writer.WritePropertyName('FirstName'); Writer.WriteValue(EmployeeTable.FieldByName('FIRST_NAME').AsString); // ... Writer.WriteEndObject; EmployeeTable.Next; end; finally EmployeeTable.Close; end; Writer.WriteEndArray; Writer.WriteEndObject; MemoLog.Lines.Clear; MemoLog.Lines.Add(StringWriter.ToString); finally Writer.Free; StringWriter.Free; end; end;
  • How can i use TJSONObjectBuilder in order to compose a JSON composed by many records added in a while cycle? For Example: if Request.QueryFields.Count > 0 then begin qry.SQL.Text := 'select * from employee where EMP_NO between :min and :max'; qry.Params.ParamByName('min').AsString := Request.QueryFields.values['min']; qry.Params.ParamByName('max').AsString := Request.QueryFields.Values['max']; end else begin qry.SQL.Text := 'select * from employee;'; end; Builder .BeginObject .BeginArray('employees') while (not qry.Eof) do begin .BeginObject .Add('EmployeeNumber',TJSONNumber.Create( qry.FieldByName('EMP_NO').AsInteger )) .Add('FirstName',qry.FieldByName('FIRST_NAME').AsString ) .Add('LastName',qry.FieldByName('LAST_NAME').AsString ) .Add('PhoneExt',qry.FieldByName('PHONE_EXT').AsString ) .Add('HireDate',qry.FieldByName('HIRE_DATE').AsString ) .Add('DepartmentNumber',TJSONNumber.Create( qry.FieldByName('DEPT_NO').AsInteger )) .Add('JobCode',qry.FieldByName('JOB_CODE').AsString ) .Add('JobGrade',qry.FieldByName('JOB_GRADE').AsString ) .Add('JobCountry', qry.FieldByName('JOB_COUNTRY').AsString ) .Add('Salary', TJSONNumber.Create( qry.FieldByName('SALARY').AsFloat )) .EndObject; qry.Next; end; .EndArray .EndObject;
  • I agree and wouldn't take much to do
  • This makes the most sense since it will fire anytime a change is made to the JsonText in TJSONDocument.
  • I will try the update method(s) you mentioned. The odd thing is that I cannot add any text to the component in design time.
  • Might be better to code the OnChange event directly in the treeview component to monitor changes in the JSONtext
  • Or use the OnChange of the JSONDocument to force a reload of the data procedure TForm1.Button1Click(Sender: TObject); begin JSONDocument1.JsonText := '{"name":"mike","value":1}'; end; procedure TForm1.JSONDocument1Change(Sender: TObject); begin JSONTreeView1.LoadJson; end;
  • I found if you set it at design time it was fine, but changing the JSON text on the JSONDocument linked to a JSONTreeview didn't update the nodes at runtime. Unhooking, then reassigning after setting the JSONText forced it to do a refresh JSONTreeView1.JSONDocument := nil; JSONDocument1.JsonText := '{"name":"mike","value":1}'; JSONTreeView1.JSONDocument := JSONDocument1;