#1 Re: mORMot 1 » Does mormot support asynchronous access? » 2019-01-24 12:57:09

@ab, There is also an unanswered question about this subject here https://synopse.info/forum/viewtopic.php?pid=28888
Can you explain this subject more?
AsynchRedirect seems the best way to implement asynchronous calls especially when you do not have a UI and using Linux so does not have Windows messages and want to prevent locks in case of calling server in a callback.

#2 Re: mORMot 1 » AsynchRedirect usage example » 2019-01-24 12:54:10

@ab,
It is the only search result about AsynchRedirect that has sample code.
Can you make documentation more clear or give a simple sample on this subject? because as you mentioned in the doc it seems using AsynchRedirect is the only good way to prevents locks (For example calling server again in the callback)

#4 Re: mORMot 1 » RegisterCustomSerializerFieldNames bug » 2018-12-03 20:22:25

Thanks you very much ab.
Can I ask why TShort63?

#5 Re: mORMot 1 » RegisterCustomSerializerFieldNames bug » 2018-12-02 16:11:49

@ab I found the bug, it was because of pointers.
I solved it temporarily.

@@ -49046,7 +49046,7 @@ type
     Reader: TJSONSerializerCustomReader;
     Writer: TJSONSerializerCustomWriter;
     Props: PPropInfoDynArray;
-    Fields: PShortStringDynArray; // match Props[] order
+    Fields: TShortStringDynArray; // match Props[] order
     Kind: TJSONObject;
   end;
   TJSONCustomParsers = array of TJSONCustomParser;
@@ -49136,7 +49136,7 @@ var i: integer;
 begin
   if Parser^.Props<>nil then begin // search from RegisterCustomSerializerFieldNames()
     for i := 0 to length(Parser^.Fields)-1 do
-      if IdemPropNameU(Parser^.Fields[i]^,PropName,PropNameLen) then begin
+      if IdemPropNameU(Parser^.Fields[i],PropName,PropNameLen) then begin
         result := Parser^.Props[i];
         exit;
       end;
@@ -49148,7 +49148,7 @@ end;
 class procedure TJSONSerializer.RegisterCustomSerializerFieldNames(aClass: TClass;
   const aClassFields, aJsonFields: array of ShortString);
 var prop: PPropInfoDynArray;
-    field: PShortStringDynArray;
+    field: TShortStringDynArray;
     n,p,f: integer;
     found: boolean;
     parser: PJSONCustomParser;
@@ -49167,7 +49167,7 @@ begin
     for f := 0 to high(aClassFields) do // check customized field name
       if IdemPropName(prop[p].Name,aClassFields[f]) then begin
         if aJsonFields[f]<>'' then begin // '' to ignore this property
-          field[n] := @aJsonFields[f];
+          field[n] := aJsonFields[f];
           prop[n] := prop[p];
           inc(n);
         end;
@@ -49175,7 +49175,7 @@ begin
         break;
       end;
     if not found then begin // default serialization of published property
-      field[n] := @prop[p].Name;
+      field[n] := prop[p].Name;
       prop[n] := prop[p];
       inc(n);
     end;
@@ -52475,7 +52475,7 @@ begin
         raise EParsingException.CreateUTF8('%.WriteObject woDontStoreInherited '+
           'after RegisterCustomSerializerFieldNames(%)', [self,aClassType]) else
         for i := 0 to length(parser^.Props)-1 do begin
-          CustomPropName := parser^.Fields[i];
+          CustomPropName := @parser^.Fields[i];
           WriteProp(parser^.Props[i]);
         end;
   end else

#6 Re: mORMot 1 » RegisterCustomSerializerFieldNames bug » 2018-11-26 16:04:20

Yes, so I will wait for him to validate my findings.

#7 Re: mORMot 1 » RegisterCustomSerializerFieldNames bug » 2018-11-26 15:14:58

Thank you Ehab.
Yes you are right about the JSON, but the problem is still there.
TClass1 and TClass2 are inherited from same class but I checked with different classes that inherited from TSynAutoCreateFields and RegisterCustomSerializerFieldNames will use only the last custom serializer.
@ab , can you validate this?

#8 mORMot 1 » RegisterCustomSerializerFieldNames bug » 2018-11-15 17:34:22

mohsenti
Replies: 9

Hi,

It seems RegisterCustomSerializerFieldNames has a bug when I use more than one custom field name for more than one class.
The second register will override the first one and it is odd because they are different classes.
I can't use record serialization because inheritance is a need.

program project1;

uses
  SynCommons,
  mORMot;

type

  { TBaseClass }

  TBaseClass = class(TSynAutoCreateFields)
  private
    fName: string;
  published
    property Name: string read fName write fName;
  end;

  { TClass1 }

  TClass1 = class(TBaseClass)
    private
      ftype_: string;
    published
      property type_: string read ftype_ write ftype_;
  end;

  { TClass2 }

  TClass2 = class(TBaseClass)
    private
      fclass_: string;
    published
      property class_: string read fclass_ write fclass_;
  end;

  { TTestClass }

  TTestClass = class(TSynAutoCreateFields)
  private
    fCount: integer;
    fObject1: TClass1;
    fObject2: TClass2;
  published
    property Count: integer read fCount write fCount;
    property Object1: TClass1 read fObject1;
    property Object2: TClass2 read fObject2;
  end;

var
  JsonString: RawUTF8;
  Obj: TTestClass;

begin
  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass1, ['type_'], ['type']);
  TJSONSerializer.RegisterCustomSerializerFieldNames(TClass2, ['class_'], ['class']);
  JsonString := '{"Count":2,"Object1":{"Name":"C1","type_":"TYPE"},"Object2":{"Name":"C2","class_":"CLASS"}}';
  Obj := TTestClass.Create;
  WriteLn(ObjectLoadJSON(Obj, JsonString, nil, JSONTOOBJECT_TOLERANTOPTIONS));
  WriteLn(ObjectToJSON(Obj, [woHumanReadable]));
  Obj.Free;
  ReadLn;
end.

#9 Re: mORMot 1 » WebSockets memory usage » 2018-06-16 15:46:10

I just did it and it seems you are right. 430mb for 2000 user.
@ab Can you comment on this and what settings I can set?

#10 Re: mORMot 1 » WebSockets memory usage » 2018-06-16 15:15:32

Nice point.
So what can I do for supporting many concurrent users?

#11 mORMot 1 » WebSockets memory usage » 2018-06-16 13:44:28

mohsenti
Replies: 4

Hi,

I wanted to try WebSockets chat test with many clients so I made this example that runs many clients at once.
The problem is for 50 clients, Server will use around 50mb of memory and it seems very high.
Using last mORMot, Windows10 and FPC 3.1.1.
Can somebody show me how should I config server and clients?

Server code:

program Server;

{$R *.res}

uses
  ChatUnit,
  SynCommons,
  mORMot,
  SynBidirSock,
  mORMotHttpServer;

var
  HttpServer: TSQLHttpServer;
  Srv: TSQLRestServerFullMemory;
begin
  Srv := TSQLRestServerFullMemory.CreateWithOwnModel([]);
  try
    Srv.ServiceDefine(TChatService, [IChatService], sicShared).SetOptions([], [optExecLockedPerInterface]).ByPassAuthentication := True;
    HttpServer := TSQLHttpServer.Create('8888', [Srv], '+', useBidirSocket);
    try
      HttpServer.WebSocketsEnable(Srv, ChatKey);
      TextColor(ccLightGreen);
      WriteLn('Server is live');
      ReadLn;
    finally
      HttpServer.Free;
    end;
  finally
    Srv.Free;
  end;
end.

Client code:

unit ManyClientsMain;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, Forms, Controls, Graphics, Dialogs,
  ChatUnit, SynCommons, mORMot, mORMotHttpClient;

type
  TClient = record
    HttpClient: TSQLHttpClientWebsockets;
    Service: IChatService;
    Callback: TChatCallback;
  end;

  { TForm1 }

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
  const
    CltsCount = 100;
  var
    Clts: array of TClient;
    procedure NewMsg(Sender: TObject);
  public

  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
var
  i: integer;
begin
  Randomize;
  SetLength(Clts, CltsCount);
  for i := 0 to CltsCount - 1 do
    with Clts[i] do
    begin
      HttpClient := TSQLHttpClientWebsockets.Create('127.0.0.1', '8888', TSQLModel.Create([]));
      HttpClient.Model.Owner := HttpClient;
      HttpClient.WebSocketsUpgrade(ChatKey);
      HttpClient.ServerTimeStampSynchronize;
      HttpClient.ServiceDefine([IChatService], sicShared);
      HttpClient.Services.Resolve(IChatService, Service);
      Callback := TChatCallback.Create(HttpClient, IChatCallback);
      Callback.OnNotify := @NewMsg;
      Service.Join('User: ' + IntToStr(Random(1000)), Callback);
    end;
end;

procedure TForm1.NewMsg(Sender: TObject);
begin
end;

end.

#13 Re: mORMot 1 » JSON Serialization with custom naming » 2017-12-30 16:04:45

Thanks.
Do you allow me to correct it if I can? Becuase the code is still there but not working and I have projects dependent on it and it still seems a good feature in my view.
And also I don't get your explanation in the replacement with DTO because in my usage I have complicated classes with inheritance and my need is very simple, just rename trouble maker names.

#14 Re: mORMot 1 » JSON Serialization with custom naming » 2017-12-30 15:25:05

Can you example more? I use classes and I cant go with records if you mean that.
Also, can I ask why you removed that? When I use mORMot with servers that made in another language there is a high chance of using Pascal keywords like Class, Type, To, From and ...

#15 Re: mORMot 1 » JSON Serialization with custom naming » 2017-12-30 06:24:32

So is there any replacement for such feature?
Making a custom reader for just renaming seems overwork.
Unfrotuanalty I cant find the remove commit.

#16 Re: mORMot 1 » JSON Serialization with custom naming » 2017-12-28 11:10:00

This ability seems broken in last Lazarus and mORMot with 64bit fpc.
I checked the code and somehow pointer of the specific field will change in the process so in JSONCustomParsersFieldProp it cant find the correct property.
@ab do you have a test case to check?

#17 Re: mORMot 1 » Choose custom class for RegisterCustomSerializer » 2017-09-23 08:54:21

@ab is there a way for implementing such thing without problem or I'm missing something?

#18 Re: mORMot 1 » Choose custom class for RegisterCustomSerializer » 2017-09-22 08:36:27

I changed TJSONSerializerCustomReader and removed const so I can change value and made a very simple sample, I have 2 class that maybe I need them to put them in there and one has a string value and another has an integer.

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    function ValueReader(aValue: TObject; aFrom: PUTF8Char; var aValid: boolean; aOptions: TJSONToObjectOptions): PUTF8Char;
  public

  end;

  { TTestValue }

  TTestValue = class(TSynAutoCreateFields)
  private
    FName: string;
  published
    property Name: string read FName write FName;
  end;

  { TTestValue1 }

  TTestValue1 = class(TTestValue)
  private
    FValue: string;
  published
    property Value: string read FValue write FValue;
  end;

  TTestValue2 = class(TTestValue)
  private
    FValue: integer;
  published
    property Value: integer read FValue write FValue;
  end;

var
  Form1: TForm1;

implementation

{$R *.lfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
var
  tv: TTestValue;
begin
  TJSONSerializer.RegisterCustomSerializer(TTestValue, @ValueReader, nil);
  tv := TTestValue.Create;
  ObjectLoadJSON(tv, ReadFileToString('1.json'), nil, [j2oIgnoreUnknownProperty]);
  WriteLn(tv.Name);
  ObjectLoadJSON(tv, ReadFileToString('2.json'), nil, [j2oIgnoreUnknownProperty]);
  WriteLn(tv.Name);
end;

function TForm1.ValueReader(aValue: TObject; aFrom: PUTF8Char; var aValid: boolean; aOptions: TJSONToObjectOptions): PUTF8Char;
var
  op: RawUTF8;
  Values: TPUtf8CharDynArray;
  N: PUTF8Char;
begin
  FreeAndNil(aValue);
  aValid := False;
  Result := nil;
  op := UTF8ToString(aFrom);
  Values := nil;
  JSONDecode(op, ['Name'], Values);
  N := Values[0];
  WriteLn(N);
  if N = 'V1' then
    aValue := TTestValue1.Create
  else if N = 'V2' then
    aValue := TTestValue2.Create;
  Result := JSONToObject(aValue, aFrom, aValid, nil, JSONTOOBJECT_TOLERANTOPTIONS);
end;                              

for a sample JOSN like:

{
	"Name": "V1",
	"Value": "String"
}

and 2.json

{
	"Name": "V2",
	"Value": 10
}

It is a naive solution but it does not work anyway because when I call JSONToObject it brings me back to the custom reader because TTestValue1 is inherited from TTestValue. Is there a way for me to prevent it or another good way to decode a JSON and read it in 2 different class by a condition?
As you can see I don't want to write all the read and write by myself because the classes are very complicated and if I force to use a custom reader, using mORMot reader will lose the point.

#19 mORMot 1 » Choose custom class for RegisterCustomSerializer » 2017-09-22 00:42:24

mohsenti
Replies: 2

I have a sample JSON file that has a name and a class that I don't know what class will be there, for example, a button or a label so I should use TControl, but all of them have a Classname so I can decide based on it but how?
RegisterCustomSerializer will make a class and then just let me fill the properties, but I just want to choose what object it should make and the rest will be on JSON serializer.
For example:

"Name" : "Cmpt1"
//It is maybe a button or a label but it always has a ClassName
"Obj": {
"ClassName"="TButton"
......}


and my class is like:

 TMyClass= class
  published         
    property Name:String read FName write FName;
    property Obj:TControl read FObj;

How can I choose what inherited class it should choose?

#20 Re: mORMot 1 » Broken Pipe while using custom service in threads » 2017-09-07 13:57:58

Hi ab,

I install newpascal and lazarus with fpcdeluxe  and rebuild mORMot and project with that , Broken pipe exception goes away and project works fine.
I compile project with delphi and fpc in windows and all tests passed successful.

#21 Re: mORMot 1 » Broken Pipe while using custom service in threads » 2017-09-05 15:04:45

Yes, server side codes are thread safe. Broken pipe occur in client side before sending and receiving data to/from server.

#22 Re: mORMot 1 » Broken Pipe while using custom service in threads » 2017-09-05 09:42:22

Pardon me.My goal of the code is an example of my program.

ab wrote:

Please follow the forum rules.
https://synopse.info/forum/misc.php?action=rules
Don't post such extensive source code in the forum.

Thank you for attention.

I can't use StringFromFile function because I have process data before saving them in file.
After many tries I found a way to reproduce exception, if Calling server methods in a loop all process work fine but if I make a delay between request Broken pipe exception raised. Maybe it's occur because some threads closed.
Lazarus Thread window doesn't show any thread change activity except TProcessThread running and closing.

When I press continue button of Broken Pipe exception other process work fine and file send to server and receive by client.

#23 Re: mORMot 1 » Broken Pipe while using custom service in threads » 2017-09-05 06:40:00

I use below code to create HttpServer.

var
  ApiMdl: TSQLModel;
  ApiSrv: TSQLRestServerDB;
  HTTPSrv: TSQLHttpServer;

begin
  //Enable logging
  with TSQLLog.Family do
  begin
    Level := LOG_VERBOSE;
    EchoToConsole := LOG_VERBOSE;
  end;

  //Create SQLModel to serve database
  ApiMdl := TSQLModel.Create([], ROOT_NAME);

  ApiSrv := TSQLRestServerDB.Create(ApiMdl, {'1.db'}SQLITE_MEMORY_DATABASE_NAME, False);

  with ApiSrv do
  begin
    //Create missing tabales
    CreateMissingTables;

    //Register services
    ServiceDefine(TProcessService, [IProcess], sicSingle);
  end;

  //Start HttpServer
  HTTPSrv := TSQLHttpServer.Create(DEFAULT_PORT, [ApiSrv], '+', HTTP_DEFAULT_MODE);

  //Allow cross-site AJAX queries
  HTTPSrv.AccessControlAllowOrigin := '*';

  WriteLn('Processor is running. press enter to terminate Processor');
  ReadLn;

  WriteLn('Processor going to stop');

  //ApiCon.Free;
  HTTPSrv.Free;
  ApiSrv.Free;
  ApiMdl.Free;

  WriteLn('Processor stoped successfull');
end.      

And I think server use socket because when change port to 80 it say port 80 is in use.

I build project with lazarus 1.9 and FPC stable 3.0.2  and my os is linux (Manjaro) .

#24 mORMot 1 » Broken Pipe while using custom service in threads » 2017-09-04 14:51:52

mohsenti
Replies: 9

Hi ab,

I wrote a client/server RESTFul to serve image processing in server. To send files from client to server first read all file data and convert stream to RawByteString and pass data as Interface method parameter to service , because reading and writing files is too slow and cause UI freeze  I create a thread to serve reading, converting , sending , receving and saving data, to determine when data are ready using another method of service (GetProgress)  and if data are ready call another method (DownloadFile) , download file method return a rawbytestring and I write data to stream.

When I calling service methods in main thread all methods work fine but when running methods in separated thread randomly two exception occurs : 1 - Broken Pipe , 2 - File not found

1 - Broken Pipe : I don't now why this error occur when calling SendFile method of service.

2 - File not found : when calling DownloadFile method immediately after SendFile File not found exception occur while in SendFile method I only save file and send file id as result and in DownloadFile read that saved file and send it to client. It look like file bounded operators in service run after finished SendFile method.

Thread Execute method

procedure TFileThread.Execute;
var
  fs: TStream;
  Index: integer;
begin
  Synchronize(@SyncProgress);
  begin
    fs := TFileStream.Create(FFilePath, fmOpenRead);
    Index := FI.SendFile(StreamToRawByteString(fs));
    fs.Free;

    while True do
    begin
      FProgress := FI.GetProgress(Index);
      if (FProgress = 100) then
        break;
      Synchronize(@SyncProgress);
    end;

    FData := FI.DownloadFile(Index);
    Synchronize(@SyncFinish);
  end;
end; 

Service Interface

IProcessor = interface(IInvokable)
    ['{8B1806EB-39CF-4ADC-B582-CF1C27F77B3E}']
    function SendFile(Stream: RawByteString): integer;
    function GetProgress(Index: integer): integer;
    function DownloadFile(Index: integer): RawByteString;
  end; 

Service class

TProcessorService = class(TInterfacedObject, IProcessor)
  public
    function SendFile(StreamData: RawByteString): integer;
    function GetProgress(Index: integer): integer;
    function DownloadFile(Index: integer): RawByteString;
  end;

Service implementation

function TProcessorService.SendFile(StreamData: RawByteString): integer;
var
  fs: TFileStream;
  pm: TProcessModel;
  frs: TStream;
begin
  //Result := FLastIndex;
  //Save File
  fs := TFileStream.Create(IntToStr(FLastIndex) + '.jpg', fmCreate);
  frs := RawByteStringToStream(StreamData);
  frs.Position := 0;
  fs.CopyFrom(frs, frs.Size);
  fs.Free;
  
  Result := FLastIndex;
  Inc(FLastIndex);
end;

function TProcessorService.GetProgress(Index: integer): integer;
var
  I: integer;
  pm: TProcessModel;
begin
  Result := 100;
end;

function TProcessorService.DownloadFile(Index: integer): RawByteString;
var
  I: integer;
  fs: TFileStream;
begin
  fs := TFileStream.Create(inttostr(Index) + '.file', fmOpenRead);
  Result := StreamToRawByteString(fs);
  fs.Free;
end;

#25 Re: mORMot 1 » Understanding mORMot » 2017-04-10 20:28:02

Thank you very much George.
It helped me.
About mORMot it is great but it lacks simple samples or doc for learning for newbies. This is no one responsibility but that makes hard for new comers adn I think one of the reasons of why mORMot users seems less that it's many abilities and much power.

#26 Re: mORMot 1 » Understanding mORMot » 2017-04-07 13:40:01

Thanks turrican, you are very kind.
I got many multiple question in last few days and here are their links, if you git time to help:
In JSON Serializer:
https://synopse.info/forum/viewtopic.ph … 757#p23757
https://synopse.info/forum/viewtopic.ph … 821#p23821

And this is more for ab but he didint respond unfortunately:
https://synopse.info/forum/viewtopic.php?id=3893

And about making a client working offline:
https://synopse.info/forum/viewtopic.php?id=3910

I appreciate if you can help in any one.

#27 Re: mORMot 1 » Understanding mORMot » 2017-04-06 17:02:09

Thanks edwinsn and turrican. Yes I know @ab made a very well framework that can do very simple to very complicated stuff easily and I aperciate it and love to have it in the Pascal world, but the problem is, it is not welcome for new comers, yes if you spend a lot of time in the doc and source you will eventually find your way and yes a complicated framework has a learning curve but for mORMot is like you are in the middle of the jungle.

Samples folder is very good but as I said it is like a showing off mORMot abilities not a path for learning it (it needs showing off, it is FAST, BIG and GOOD).

Take OmniThreadLibrary as an example, it is complicated, not as mORMot but complicated enough in a sensitive filed, threading. but did you saw the samples? if you are very new still you can find out how it works and how it can used in your projects.
I think the reason for not having such a good way for learning it is, author dont need sample and didn't made them and everyone like you @edwinsn spent a lot of time to learn it and then again dont fell the need of making learning samples either. Also another reason is when you make a sample for such big library, you need to know it well, and maybe there is not enough people know it like that much to teach it to new comers.

Even take me as an example, I worked with multiple stuff of mORMot and the best I done until know was using it's JSON serialiser and even after days I dont know much of it so I still cant make a sample for others.

Although, One can say if you want it, work for it and yes many ones do; my point is, such a brilliant tool dont need to be like a jungle of great code and doc and samples without a map.
For someone new mORMot's documentation is like a atlas not a learning book.

#29 mORMot 1 » Understanding mORMot » 2017-04-02 14:05:54

mohsenti
Replies: 9

Hi, It is my thought in last days working with mORMot and wanted to share with you hope to get your opinion about it.

Dear ab I know you dont like to give the last answer to lazy people but Maybe it is clear for you (ab as the maker or anyone experience with the huge doc) but it is not easy to mess around with a huge doc that in the explanation will link to many places and expect you to know most of the previous doc to understand what is going on.

And the samples seem not for a newbie, they seem they added while you develop mORMot and wanted to show how it is powerful not for a new learner to learn basic unless he read the whole doc because it will link to many places like a story (and many key parts are like blog posts so it like you need to know previous back story) , you cant read a session for learning just that.

I tried to learn JSON serialization and made it work somehow with you helps but that was it can work without the other mORMot tools.

I hope you dont look at this comment as a rude one, but I read many of your posts in more than 5 years in this forum that they are explaining a task that can be very clear if there was a simple sample for it.

As an example I was trying to make a demo for JSON serialization when I learned it completely but I couldnt end it and lost in the code and couldn't get more help from you or another person.

Hope it was clear.

#30 Re: mORMot 1 » Offline cache » 2017-04-02 14:02:59

Sorry but I cant understand how it can help and I looked in the samples list an there is not one to show how it works.
I tried to change Sample 4 to make it like the doc and add TRecordVersion property and do RecordVersionSynchronizeSlave but it is not clear in the doc how it can help.

Can you point me to the working sample?

PS, https://synopse.info/forum/viewtopic.php?id=3912

#31 Re: mORMot 1 » Custom Reader for JSON Serialization with array value » 2017-04-02 13:21:03

There was sample in doc but I could not make it work and I used array for that and only for auto reader not custom readers.

#32 mORMot 1 » Offline cache » 2017-04-02 01:32:56

mohsenti
Replies: 2

Hi,

What is my best choice to have an offline read/write cache of data and changes when network connection is lost and then sync back to/from server when it back?
Can I do it with mORMot and record version? can I only have read only cache? should I make it by hand or there is a ready to use tools for it?

#37 Re: mORMot 1 » JSON Serialization with custom naming » 2017-03-27 11:20:12

Thanks!

I checked that and it makes SIGSEGV error on line 47213 "Writer := nil; // exclusive" in FPC truck.

#38 Re: mORMot 1 » Choose JSON Serialization classes » 2017-03-26 21:58:40

Thanks, but where is it?
If you mean this https://synopse.info/files/html/Synopse … ml#TITL_71 I cant understand how it can help because it need "ClassName" value but I get this JSON from another sever and the value is "Type" for example.

I'm still looking for a solution in documentation and the code and the best I found is something like this and it seems it works.

  procedure TestIt;
  var
    it: TParentItem;
    s: RawUTF8;
  begin
    TJSONSerializer.RegisterObjArrayForJSON([TypeInfo(TParentItems), TParentItem]);
    TTextWriter.RegisterCustomJSONSerializer(TypeInfo(TParentItems), TSReaderWriter.ParentItemsReader, nil);
    s := StringFromFile('test.json');
    it := TParentItem.Create;
    ObjectLoadJSON(it, s, nil, [j2oIgnoreUnknownProperty]);
    ObjectToJSONFile(it, 'output.json');
    it.Free;
  end;

  { TSReaderWriter }

  class function TSReaderWriter.ParentItemsReader(P: PUTF8Char; var aValue; out aValid: boolean): PUTF8Char;
   var
    V: TObject absolute aValue;
    typ: string;
    op:RawUTF8;
  begin
    aValid := False;
    Result := nil;
    if (p = nil) then
      exit;
    if (V = nil) then
    begin
      op:=UTF8ToString(P);
      if typ = 'C1' then
        V := TParentItem1.Create
      else if typ = 'C2' then
        V := TParentItem2.Create
      else
        V := TParentItem.Create;
    end;
    result := JSONToObject(aValue, P, aValid, nil, JSONTOOBJECT_TOLERANTOPTIONS);    
  end;                    

#39 mORMot 1 » Choose JSON Serialization classes » 2017-03-26 19:47:00

mohsenti
Replies: 3

Hi,

I have JSON like this:

{
	"ID": 1,
	"Childs": [{
			"ID": 2,
			"Typ": "C1",
			"Name1":"X"
		}, {
			"ID": 3,
			"Typ": "C2",
			"Name2":"Y"
		}
	]
}

Childs can have different classes with different types but I have an array with base Child class, so I made something like this:

type
  TParentItem = class;
  TParentItems = array of TParentItem;

  { TItem }

  TItem = class(TSynAutoCreateFields)
  private
    FID: integer;
  published
    property ID: integer read FID write FID;
  end;

  { TParentItem }

  TParentItem = class(TItem)
  private
    FChilds: TParentItems;
    FTestItem: TItem;
  published
    property TestItem: TItem read FTestItem;
    property Childs: TParentItems read FChilds write FChilds;
  end;

  { TParentItem1 }

  TParentItem1 = class(TParentItem)
  private
    FName1: string;
  published
    property Name1: string read FName1 write FName1;
  end;

  { TParentItem2 }

  TParentItem2 = class(TParentItem)
  private
    FName2: string;
  published
    property Name2: string read FName2 write FName2;
  end;              

How can I choose what class should be made for array item? I have "Typ" value to choose that but making a CustomSerializer wont help becuase it pass a const object and I can change the value of it.
Is there a way to pass a custom create function so in there I can check the "Typ" value and choose that?

#40 Re: mORMot 1 » Inheritance in JSON Serialization » 2017-03-25 13:23:57

I checked the code and it seems InternalClassPropInfo give the prop list in revers order, but I cant clearly understand how you do that but I checked FPC implementation like this and it write the list in order.

uses typinfo,Rtti;

    c: TRttiContext;
    RttiType: TRttiType;
    PropList: {$ifdef fpc}specialize{$endif} TArray<TRttiProperty>;
    i: Integer;
  begin
    c := TRttiContext.Create;
    RttiType := c.GetType(TParentItem.ClassInfo);
    PropList:=RttiType.GetProperties;
    WriteLn(Length(PropList));
    for i:=0 to Length(PropList)-1 do
    begin
     WriteLn(PropList[i].Name);// will print ID,Childs but InternalClassPropInfo give Childs first
    end;
    c.Free;    

What do you think?

#41 Re: mORMot 1 » JSON Serialization with custom naming » 2017-03-25 12:31:09

Great.
Yes I know, its a test and honestly I still trying to understand the flow of your codes. they are clean but very complicated and optimized.

#42 Re: mORMot 1 » Custom Reader for JSON Serialization with array value » 2017-03-25 12:27:10

So I done something like this:

  DA.Init(TypeInfo(TItem),V.FChilds);
  DA.LoadFromJSON(Values[2]);

The only question is how can I set the value with the property "Childs" not the exact value like "FChilds"?

#43 Re: mORMot 1 » JSON Serialization with custom naming » 2017-03-25 10:16:55

So I work more with it and find out my implementation was silly so I made a new one so you can now register custom names for a class.

TJSONSerializer.RegisterCustomNames(TItem, ['Type', 'Type_', 'Class', 'Class_']);

Please tell me what you think.
Patch:
https://ufile.io/722201

#44 mORMot 1 » JSON Serialization with custom naming » 2017-03-25 00:31:29

mohsenti
Replies: 16

Hi,

In my journey in reading JSON with mORMot, as @ab said I went to a road that I make custom serializer for my classes that need special care.
In many of these 3rd party JSONs there is only one problem; they are using identifier names like "Type", "Class" or "To" and I obviously I cant use them as property name so I saw my self making many custom reader an writer for only one property name and I think it does not seem wise so I made some changes in JSONToObject so it takes care of these "CustomNaming" and here is my changes and it works well so I can read JSON like this:

{
	"ID": 1,
	"Type": "Item",
	"Class":"Book"
}

like this:

ObjectLoadJSONWithCustomNames(it, s,nil,[],['Type','Type_','Class','Class_']);   

I changed the function code like this:

...
    PropName := GetJSONPropName(From,@PropNameLen);  // get property name
    //CustomNaming
    if Length(CustomNames) mod 2 =0 then
    begin
      cni:=0;
      while cni<=(Length(CustomNames) div 2) do
      begin
        if UTF8ToString(CustomNames[cni])=UTF8ToString(PropName) then
        begin
          PropName:=CustomNames[cni+1];
          PropNameLen:=Length(PropName);
        end;
        inc(cni,2);
      end;
    end;

    if (From=nil) or (PropName=nil) then    
... 

So I wanted to ask you @ab, is it a good practice to do the job like this?

PS, Here is the link to the patch of my changes:
https://ufile.io/c2983

#45 mORMot 1 » Custom Reader for JSON Serialization with array value » 2017-03-24 23:07:14

mohsenti
Replies: 6

Hi,

AS suggested in forum I'm trying to make a new custom reader for my JSON like document https://synopse.info/files/html/Synopse … ml#TITL_52 and it goes well.
But I dont know who to handle array values and I cant find any sample.
One of the properties is array and trying many function including JSONArrayDecode cant decode the JSON array.
What function I should use for arrays?

#46 Re: mORMot 1 » Inheritance in JSON Serialization » 2017-03-24 17:41:46

So I need a custom one. For now automated serialization works very fine on most of the classes and I wished I can change the order so it does not make me to write all of the classes by hand.

I should say your automated serialization works very well and it is the best I found in Pascal language, these options I'm talking about make it more configurable to use it easily out of an ORM too.
I can change the source if you think it is right though.

#47 Re: mORMot 1 » JSONToObject error/warning log » 2017-03-24 17:38:36

Yes I know but it makes everything much more complicated, I have many classes and automated serialization works fine for most of them, I just want a log for automated serialization.

#48 Re: mORMot 1 » Prevent making not existence classes in JSON Serialization » 2017-03-24 17:37:24

Yes but only for parent but not all the childs, I want to only make it for parent not all childs.

#49 mORMot 1 » mORMot package for Lazarus » 2017-03-24 16:19:07

mohsenti
Replies: 1

Hi,

In Lazarus packages make develop easier and because mORMot has not a package I think, I made a simple one, it makes managing project very easier so you dont need to add path to mORMot every time or add include path or SQLite ... . Also it let you to chose custom compile options and debug modes. As I said very useful for manage project in Lazarus.

This sample package should save in mORMot folder under "Package" folder.
For now it only includes only same base unit, if ab like the idea I can add all the needed units.

Download link:
https://ufile.io/c4aa2

@ab, what do you think?

PS, its good to have attachment ability in the forum.

Board footer

Powered by FluxBB