You are not logged in.
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
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
@ab is there a way for implementing such thing without problem or I'm missing something?
Offline