#1 2017-09-22 00:42:24

mohsenti
Member
Registered: 2015-04-11
Posts: 72

Choose custom class for RegisterCustomSerializer

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?

Offline

#2 2017-09-22 08:36:27

mohsenti
Member
Registered: 2015-04-11
Posts: 72

Re: Choose custom class for RegisterCustomSerializer

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.

Offline

#3 2017-09-23 08:54:21

mohsenti
Member
Registered: 2015-04-11
Posts: 72

Re: Choose custom class for RegisterCustomSerializer

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

Offline

Board footer

Powered by FluxBB