Trying to convert an object to JSON at run time, I'm getting insufficient RTTI Error. The object is:
{$M+}
{$TYPEINFO ON}
{$METHODINFO ON}
{$RTTI EXPLICIT METHODS([vcPublic, vcPublished]) PROPERTIES([vcPublic, vcPublished])}
TMyPacket = class(TObject)
Private
FID: TGUID;
FToIP: string;
FToPort: integer;
FSent: boolean;
FSentAt: TDateTime;
FAck: boolean;
FTimeOut: Cardinal;
FDataToSendSize: UINT64;
FDataToSend: AnsiString;
public
constructor create;
destructor free;
published
property ID: TGUID read FID write FID;
property ToIP: string read FToIP write FToIP;
property ToPort: integer read FToPort write FToPort;
property Sent: boolean read FSent write FSent;
property SentAt: TDateTime read FSentAt write FSentAt;
property Ack: boolean read FAck write FAck;
property TimeOut: Cardinal read FTimeOut write FTimeOut;
property DataToSend: AnsiString read FDataToSend write FDataToSend;
end;
later in the code:
var fpacket: TMYPacket;
begin
fpacket := TVWTCPPacket.create;
//assign value to class properties
memo1.Lines.Text := TJson.ObjectToJsonString(fpacket); //throws error
and getting the error on JSON conversion. Does anyone have any idea on whats going wrong with Delphi Berlin 10.1? I do remember some RTTI issues on XE2 but not sure what is happening above is related to Delphi old bug or not.
Go into System.Rtti
and put a breakpoint into TRttiField.GetValue
at the line if ft = nil then
and put a breakpoint condition ft = nil
(if you would put the breakpoint in the next line you would not be able to see what the Name of the field was because of optimization).
When your debugger stops there you can inspect Self.Name
(Ctrl+F7) and it will tell you D4
which is the fourth field of your TGuid. This is because JsonReflect recursively serializes records by serializing their fields. Because D4
is declared as array[0..7] of Byte
it does not contain type info (see also).
To solve this create your own type interceptor for TGUID
:
type
TGuidInterceptor = class(TJSONInterceptor)
public
function StringConverter(Data: TObject; Field: string): string; override;
procedure StringReverter(Data: TObject; Field: string; Arg: string); override;
end;
function TGuidInterceptor.StringConverter(Data: TObject;
Field: string): string;
var
ctx: TRttiContext;
begin
Result := ctx.GetType(Data.ClassInfo).GetField(Field).GetValue(Data).AsType<TGuid>.ToString;
end;
procedure TGuidInterceptor.StringReverter(Data: TObject; Field, Arg: string);
var
ctx: TRttiContext;
begin
ctx.GetType(Data.ClassInfo).GetField(Field).SetValue(Data, TValue.From(TGuid.Create(Arg)));
end;
and mark the field accordingly:
[JsonReflect(ctString, rtString, TGuidInterceptor)]
FID: TGUID;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With