TMS Aurelius version 1.7, released a couple of weeks ago, introduced a new feature that was often requested by users: JSON support. You may ask yourself, why is that so important? Can't I "use JSON" already with Delphi itself using JSONMarshal class, or even by a 3rd party library like Super Object?
Well, yes and no. Actually there are already many people using Aurelius in distributed applications, using it with DataSnap, REST servers. etc.. My previous blog post is an example of that. If you have in your application simple entity classes like this:
[Entity, Automapping] TCustomer = class private FId: Integer; FName: string; FCity: string; public property Id: Integer read FId write FId; property Name: string read FName write FName; property City: string read FCity write FCity; end;Then it would work smoothly. One of the things I like most in Aurelius is your entity classes can be very simple. You can use simple types, simple objects, don't need to inherit from a specific class or override methods. So you can build your entity classes the way it will fit for your application, in this case, make them simple to transfer them between your client and server.
But you might also want to benefit from many Aurelius features: nullable types, lazy-loading, blob support, associations, lists. That's when the problem arises. Most JSON libraries don't handle them correctly. Some of them allow you to add some custom converters and attributes that maybe would make it happen, but it would pollute your class (why add extra meta information when your mapping is already done) and probably will require many hours of extra effort to make it work.
So, that 's the reason for this new feature - it takes advantage of the mapping information for the serialization and deserialization. Aurelius already knows which fields/properties are important (mapped), the custom types, the lists, associations, etc.. So for example, to build a DataSnap REST server that has methods returning objects, you can simply implement your server methods like this;
function TBugTrackerMethods.LoadIssue(Id: integer): TJsonValue; begin Result := FSerializer.ToJson(FManager.Find<TIssue>(Id)); end; procedure TBugTrackerMethods.SaveIssue(Issue: TJsonValue); begin FManager.SaveOrUpdate(FDeserializer.FromJson<TIssue>(Issue)); FManager.Flush; end; function TBugTrackerMethods.ListIssuesByProject(ProjectId: integer): TJsonValue; var IssueList: TList<TIssue>; begin IssueList := FManager.Find<TIssue> .SubCriteria('Project') .Where(TLinq.IdEq(ProjectId)) .List<TIssue>; try Result := FSerializer.ToJson(IssueList); finally IssueList.Free; end; end;It doesn't matter how complex a TIssue class is built. Actually all the structure was built not only to make it easy to send/receive Aurelius objects, but also to mimic the behavior of TObjectManager class, if needed. So if you have an existing client-server Aurelius application, changing it to retrieve objects from a remove application server instead of database should be very simple and straightforward. Associations are fully supported, even with lazy-loading. Even from non-Delphi clients, like JavaScript, the client you will write will look very similar to a Delphi application using Aurelius. The following code is an example in JavaScript (using JQuery) that communicates with the DataSnap server mentioned above. It loads an issue from the server (using an ID provided by the user) and allows you to close or cancel the issue by clicking buttons:
var issue = null; $(document).ready(function() { $('#issuediv').hide(); $('#searchButton').click(function(event) { issue = serverMethods().LoadIssue(issueIdField.value).result; $('#issuediv').show(); $('#idField').val(issue.Id); $('#subjectField').val(issue.Subject); $('#priorityField').val(issue.Priority); $('#statusField').val(issue.Status); $('#assignedToField').val(issue.AssignedTo.Name); $('#projectField').val(issue.Project.Name); $('#descriptionField').val(issue.Description); }); $('#closeButton').click(function(event) { issue.Status = 'Closed'; serverMethods().SaveIssue(issue); $('#issuediv').hide(); }); $('#cancelButton').click(function(event) { issue.Status = 'Canceled'; serverMethods().SaveIssue(issue); $('#issuediv').hide(); }); });A final note: the serializer/deserializer can use any JSON parser library you want. Currently both Delphi (DataSnap) and SuperObject are supported, but architecture is build in a way that any other library can be used.