1

I'm trying to serialise/deserialise the TMySerializableClass declared in the below unit:

unit Unit6;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Generics.Collections, System.SyncObjs, DBXJSon,
  DBXJSonReflect;

type
  TForm6 = class(TForm)
    Button1: TButton;
    Memo1: TMemo;
    procedure Button1Click(Sender: TObject);
  private
  public
    { Public declarations }
  end;

  TMySerializableClass<T> = class
    MyStringField: string;
    MyIntegerField: Integer;
    MyBooleanField: Boolean;
  end;

var
  Form6: TForm6;

implementation

{$R *.dfm}

procedure TForm6.Button1Click(Sender: TObject);
var
  Mar: TJSONMarshal;  //Serializer
  UnMar: TJSONUnMarshal;  //UnSerializer
  SerializedObject: TJSONObject;
  aMySerializableClass1: TMySerializableClass<Integer>;
  aMySerializableClass2: TMySerializableClass<Integer>;
  aString: string;
begin
  try
    aMySerializableClass1:= TMySerializableClass<Integer>.Create;
    aMySerializableClass2:= TMySerializableClass<Integer>.Create;

    Mar:= TJSONMarshal.Create(TJSONConverter.Create);
    try
      SerializedObject := Mar.Marshal(aMySerializableClass1) as TJSONObject;
    finally
      Mar.Free;
    end;
    Memo1.Text:= SerializedObject.ToString;

    // UnMarshalling Kid
    UnMar := TJSONUnMarshal.Create;
    try
      aMySerializableClass2 := UnMar.UnMarshal(SerializedObject) as TMySerializableClass<Integer>;
    finally
      UnMar.Free;
    end;
  finally
    aMySerializableClass1.Free;
    aMySerializableClass2.Free;
  end;
end;

end.

When I serialise it everything works fine, while when deserialise to a new instantiated variable of the same kind I got the following error:

First chance exception at $74E5C41F. Exception class EConversionError with message 'Internal: Cannot instantiate type Unit6.TMySerializableClass<System.Integer>'. Process Project7.exe (2252)

Edit: this has something to do with the TMySerializableClass<T>, which is a generic. If I declare it as TMySerializableClass the deserialisation works fine.

Ideas?

Marco Carboni
  • 283
  • 1
  • 12

1 Answers1

0

Cannot test on XE5 but on Berlin 10.1 it worked for me after I added alias for instance of generic type as

TMySerializableClassInteger = TMySerializableClass<Integer>;

looks like Delphi does not generate RTTI information if you don't do it.

UPDATE. Seems Delphi does not need alias but just have some declaration of specialized class in interface part of the unit. So if you declare variable or form field as TMySerializableClass<Integer> it will also work.

EugeneK
  • 2,164
  • 1
  • 16
  • 21
  • 1
    This defeats the use of Generics, no? – whosrdaddy Jan 17 '17 at 09:57
  • It's a dirty trick as I have to use more code and check / instantiate different classes, but I can live with this for what I need to do now. Just for sake of knowledge it's likely a bug in Delphi or we are doing something basically wrong? – Marco Carboni Jan 17 '17 at 10:11
  • 1
    For future readers, I suggest using https://github.com/onryldz/x-superobject to deal with Json related problems . The units DBXJSon seems buggy, and REST.JSON too. REST.JSON solves the problem in this case (with the generic class) but it seems like it's not a good choice (see this post : http://stackoverflow.com/questions/31778518/delphi-rest-json-jsontoobject-only-works-with-f-variables) – Etsitpab Nioliv Jan 17 '17 at 10:28
  • 1
    @MarcoCarboni there seems to be another workaround - it seems Delphi does not need alias but just have some declaration of specialized class in interface part of the unit. So if you declare variable of form field as TMySerializableClass it will also work. – EugeneK Jan 17 '17 at 17:55