If you start to use or migrate your application to the new DataSnap you may ask how to transfer objects between client/server. The data types allowed to be transfered in DataSnap 2009 is limited to the dbExpress data types, but in DataSnap 2010 part of Delphi 2010 you are allowed to transfer any kind of object.
DataSnap 2010 brings support for JSON (JavaScript Object Notation), which is a lightweight data-interchange format, easy for humans to read/write and easy for machines to parse and generate, also independent of language. In a future post I will expand on JSON advantages. To start I will explain how to transfer an object between DataSnap Win32 client and server.
Let’s define the object we would like to transfer, class TCustomer.
unit Customer; interface uses DBXJSON, DBXJSONReflect, SysUtils; type TMaritalStatus = (msMarried, msEngaged, msEligible); TCustomer = class private FName: string; FAge: integer; FMaritalStatus: TMaritalStatus; public property Name: string read FName write FName; property Age: integer read FAge write FAge; property MaritalStatus: TMaritalStatus read FMaritalStatus write FMaritalStatus; function toString : string;override; end;
Only objects that descend from TJSONObject are able to be transferred between client and server without any transformation in DataSnap 2010. If your object does not descend from TJSONObject, then you have to use the TJSONMarshal and TJSONUnMarshal classes to convert those objects. The example below shows how to make this conversion.
unit Customer; function CustomerToJSON(customer: TCustomer): TJSONValue; var m: TJSONMarshal; begin if Assigned(customer) then begin m := TJSONMarshal.Create(TJSONConverter.Create); try exit(m.Marshal(customer)) finally m.Free; end; end else exit(TJSONNull.Create); end; function JSONToCustomer(json: TJSONValue): TCustomer; var unm: TJSONUnMarshal; begin if json is TJSONNull then exit(nil); unm := TJSONUnMarshal.Create; try exit(unm.Unmarshal(json) as TCustomer) finally unm.Free; end; end;
You don’t need to implement two transformation methods for every single class, you can implement a generic method for class that use simple data types, I mean strings, numbers, boolean. Due to the fact that some support classes can be quite complex and some types are fully supported by the current RTTI runtime converters can be added. I will not focus on converters, instead I recommend you to read this post from Adrian Andrei our RAD Studio Database Architect.
At this point we have the TCustomer class ready to cross between client and server, in this case now we just need to implement a Server Method which return a TJSONValue after the TCustomer transformation, like the example below.
// protected function TServerMethods.GetCustomer: TCustomer; begin Result := TCustomer.Create; Result.Name := 'Pedro'; Result.Age := 30; Result.MaritalStatus := msEligible; end; // public function TServerMethods.GetJSONCustomer(): TJSONValue; var myCustomer: TCustomer; begin myCustomer := GetCustomer; Result := CustomerToJSON(myCustomer); myCustomer.Free; end;
Executing the method GetJSONCustomer from the client side will be necessary to convert the method return from TJSONValue to TCustomer, using the method JSONToCustomer.
var proxy: TServerMethodsClient; myJSONCustomer: TCustomer; begin try proxy := TServerMethodsClient.Create(SQLConnection1.DBXConnection); myJSONCustomer := JSONToCustomer(proxy.myJSONCustomer); Button1.Caption := myJSONCustomer.ToString; myJSONCustomer.Free; finally SQLConnection1.CloneConnection; proxy.Free; end; end;
Much more can be done, for example return an Array of objects, complex classes, etc. In future posts I will comment about that.
The source code is available for download
Related Posts
Andreano Lanusse | Technology and Software Development
Follow me on Twitter: @andreanolanusse