我正在尝试使用TJSONMarshal(XE4)序列化对象,但是当对象具有像_recordset
这样的接口属性时我遇到了问题e.g。
我的课程:
TFoo = class
private
FrsFoo: _recordset;
FFooProp: integer;
published
property rsFoo: _recordset read FrsFoo write FrsFoo;
property FooProp: integer read FFooProp write FFooProp;
end;
我的功能:
function TestSerialize: string;
var
JsonMarshal: TJSONMarshal;
Foo: TFoo;
begin
JsonMarshal := TJSONMarshal.Create(TJSONConverter.Create);
Foo := TFoo.Create;
Result := JsonMarshal.Marshal(Foo).ToString;
end;
结果:
{ “类型”: “uTest.TFoo”, “ID”:1, “字段”:{ “FFooProp”:0}}
rsFoo未序列化!
我可以序列化吗?或者它是TJSONMarshal的限制?
答案 0 :(得分:1)
在我的情况下,我只是想序列化_recordsets,所以我的解决方案是:
1)获取所有_Recordset类型字段:
function Test.GetRecordsetFieldsFromObject(
AObject: TObject): TStringList;
var
Obj: TRttiType;
Rtti: TRTTIContext;
ObjField: TRttiField;
IntfObj: IInterface;
rsOut: _recordset;
begin
Result := TStringList.Create;
Obj := Rtti.GetType(AObject.ClassType);
for ObjField in Obj.GetFields do
if ObjField.FieldType.TypeKind = tkInterface then
begin
IntfObj := ObjField.GetValue(AObject).AsInterface;
if IntfObj.QueryInterface(_Recordset, rsOut) = 0 then
begin
Result.Add(ObjField.Name);
rsOut := nil;
end;
end;
end;
2)为每个创建的领域注册转换器和转换器
for FieldName in FieldNameList do
begin
JsonMarshal.RegisterConverter(TFoo, FieldName, function(Data: TObject; Field: String): TListOfStrings
var
Obj: TRttiType;
ObjField: TRttiField;
rsProp: _Recordset;
strStream: TStringStream;
begin
SetLength(Result, 1);
strStream := TStringStream.Create;
try
Obj := Rtti.GetType(data.ClassType);
ObjField := Obj.GetField(Field);
rsProp := ObjField.GetValue(Data).AsInterface as _Recordset;
rsProp.Save(TStreamAdapter.Create(strStream) as IUnknown, adPersistXML);
Result[0] := strStream.DataString;
finally
rsProp := nil;
strStream.Free;
end;
end);
JsonUnMarshal.RegisterReverter(TFoo, FieldName, procedure(Data: TObject; Field: String; Args: TListOfStrings)
var
Obj: TRttiType;
ObjField: TRttiField;
rsProp: _Recordset;
strStream: TStringStream;
begin
rsProp := coRecordset.Create;
strStream := TStringStream.Create(Args[0]);
try
Obj := Rtti.GetType(data.ClassType);
ObjField := Obj.GetField(Field);
strStream.Position := 0;
rsProp.Open(TStreamAdapter.Create(strStream) as IUnknown, EmptyParam, adOpenUnspecified, adLockUnspecified, 0);
ObjField.SetValue(Data, TValue.From<_Recordset>(rsProp));
finally
rsProp := nil;
strStream.Free;
end;
end);
end;