Reputation: 51
I'd like to serialize objects and records to send them and restore on a remote endpoint. There is the shared objects declaration unit for a local and remote end.
I has a record with a field containing different records as JSON Object:
TPmMessage = record
CorrelationId: TGUID;
BatchId: TGUID;
MessageName: string;
Data: ISuperObject; // TAlarms, TCommand record and etc. can be inside as JSON object
end;
I need to write a Type name (TRttiType.QualifiedName) in a JSON object for the Data field for deserialization on other side.
An example structure:
TDeviceInfo = record
DeviceType: string;
DeviceIp: string;
end;
TAlarmLocation = record
Name: string;
rack: Word;
slot: Word;
port: Word;
end;
TAlarmInfo = record
AlarmType: string;
Severity: string;
ConditionType: string;
Datetime: TDateTime;
Location: TAlarmLocation;
end;
TAlarm = record
DeviceInfo: TDeviceInfo;
Alarm: TAlarmInfo;
end;
TAlarmsList = array of TAlarmInfo;
Usage:
var
msg: TPmMessage;
als: TAlarms;
ctx: TSuperRttiContext;
JsonText: string;
begin
ctx := TSuperRttiContext.Create;
try
SetLength(als,2);
// init array of als
...
// init TPmMessage Fields
...
// serialize TAlarms
msg.Data := ctx.AsJson<TAlarms>(als);
// serialize TPmMessage
JsonText := ctx.AsJson<TPmMessage>(msg).AsString;
...
// Restore record from JSON object
msg := ctx.AsType<TPmMessage>(SO(JsonText));
...
finally
ctx.Free;
end;
end;
After restore I get an TPmMessage, but I don't know what type in the Data JSON object.
In case 1 I don't know the type of the Data JSON object. So I added the DataObjectType field with QualifiedName as value.
In that case I make another structure for seralization:
TPmMessageData = record
DataObjectType: string;
DataObject: ISuperObject;
end;
TPmMessage = record
Source: string;
CorrelationId: TGUID;
BatchId: TGUID;
MessageName: string;
Data: TPmMessageData;
end;
This structure serialized correctly with code:
var
msg: TPmMessage;
ti: PTypeInfo;
uals: TAlarms;
begin
{fill Alarms array}
ti := TypeInfo(TAlarms);
msg.Data.DataObjectType := ctx.Context.GetType(ti).QualifiedName;
msg.Data.DataObject := ctx.AsJson<TAlarms>(uals);
end;
DataObject: ISuperObject also serialised well.
A question is How to deserialize the DataObject?
I thought that it's possioble to use
{var DataType: TRttiType;}
DataType := ctx.Context.FindType(DecodedMsg.Data.DataObjectType);
uals := ctx.AsJson<DataType>(DecodedMsg.Data.DataObject);
But the Method 'AsType' requires explicit type argument.
So I think to use case to set the correct type is the only way.
How to serialize/deserialise by using superobject beter?
Could you suggest me a better structure for the messages instead of this?
Upvotes: 3
Views: 3529
Reputation: 36634
You could wrap the JSON serialized object in a container object which has two properties:
then in the deserialization, first read the type of the contained object and then load the serialized object into a Delphi object variable of the corresponding type.
However, a interface pointer in a record is not easy to serialize anyway (it contains a pointer instead of a full JSON encoded string) - so I am not sure if the record serialization fails for a different reason.
Upvotes: 1