Delphi: суперобъектная сериализация пользовательского преобразователя/инвертора

90
12

Я хотел бы сериализовать объекты и записи для их отправки и восстановления на удаленной конечной точке.
Существует единица объявления общих объектов для локального и удаленного конца.


У меня есть запись с полем, содержащим разные записи как объект JSON:


TPmMessage = record
CorrelationId: TGUID;
BatchId: TGUID;
MessageName: string;
Data: ISuperObject; // TAlarms, TCommand record and etc. can be inside as JSON object
end;

CASE 1


Мне нужно написать имя типа (TRttiType.QualifiedName) в объекте JSON для поля Data для десериализации на другой стороне.


Пример структуры:


  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;


Использование:


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;

После восстановления я получаю TPmMessage, но я не знаю, какой тип в объекте Data JSON.


CASE 2


В случае 1 я не знаю тип объекта Data JSON. Поэтому я добавил поле DataObjectType с QualifiedName как значение.


В этом случае я создаю еще одну структуру для серализации:


  TPmMessageData = record
DataObjectType: string;
DataObject: ISuperObject;
end;

TPmMessage = record
Source: string;
CorrelationId: TGUID;
BatchId: TGUID;
MessageName: string;
Data: TPmMessageData;
end;


Эта структура сериализована правильно с кодом:


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 также хорошо сериализуется.


Вопрос: как десериализовать DataObject?


Я думал, что возможно использовать


{var DataType: TRttiType;}
DataType := ctx.Context.FindType(DecodedMsg.Data.DataObjectType);
uals := ctx.AsJson<DataType>(DecodedMsg.Data.DataObject);

Но для метода "AsType" требуется явно аргумент типа.


Поэтому я думаю, что использовать случай для установки правильного типа - это единственный способ.


Как сериализовать/десериализовать с помощью суперобъекта beter?


Не могли бы вы предложить мне лучшую структуру для сообщений вместо этого?

спросил(а) 2021-01-19T22:21:49+03:00 6 месяцев, 1 неделя назад
1
Решение
63

Вы можете обернуть сериализованный объект JSON в объект-контейнер, который имеет два свойства:


    имя типа
    завернутый объект

то в десериализации сначала прочитайте тип содержащегося объекта, а затем загрузите сериализованный объект в объектную переменную Delphi соответствующего типа.


Однако указатель интерфейса в записи не так-то просто сериализовать (он содержит указатель вместо полной JSON-кодированной строки) - поэтому я не уверен, что сериализация записи завершилась неудачно по другой причине.

ответил(а) 2021-01-19T22:21:49+03:00 6 месяцев, 1 неделя назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема