'EInsufficientRTTI exception with message 'Insufficient RTTi available to support this operation'

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.



Solution 1:[1]

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;

Solution 2:[2]

There is no RTTI generated for TGUID kind of fields.

So in order to serialize your class, you may just use getter/setter functions, which set a string property.

Something like:

TMyPacket = class(TObject)
  Private
    FIDValue: TGUID;
    FToIP: string;
    FToPort: integer;
    FSent: boolean;
    FSentAt: TDateTime;
    FAck: boolean;
    FTimeOut: Cardinal;
    FDataToSendSize: UINT64;
    FDataToSend: AnsiString;
    procedure SetID(const value: string);
    function GetID: string;
  public
    constructor create;
    destructor free;
    property IDValue: TGUID read FID write FID;
  published
    property ID: string read GetID write SetID;
    property ToIP: string read FToIP write FToIP;
    property ToPort: integer read FToPort write FToPort
  ...

procedure TMyPacket.SetID(const value: string);
begin
  fIDValue := StringToGUID(value);
end;

function TMyPacket.GetID: string;
begin
  result := GUIDToString(fIDValue);
end;

Then serialization should work, with a "ID": string field, and you will get the TGUID value in the IVValue public property.

Solution 3:[3]

check if this lines exists in the dpr file, if it exists you have to delete it

{$IFOPT D-}{$WEAKLINKRTTI ON}{$ENDIF}
{$RTTI EXPLICIT METHODS([]) PROPERTIES([]) FIELDS([])}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Community
Solution 2 Arnaud Bouchez
Solution 3 bigbear2