Search code examples
delphidelphi-xe6

Trouble converting delphi objects with arrays to json


I've been trying to translate my objects into a json string with TJson.ObjectToJsonString(object). It works fine for simple objects but it will break if the object contains an array(static or dynamic). What's the correct way of creating an json string of an object? I've looked at TSuperObject but it wasn't apparent what I would need to do.

Class structure

TPerson = class(TObject)
private
  FID       : integer;
  FLastName : string;
  FFirstName: string;
  FEmail    : string;
  fMyArray : array[0..2] of boolean;

  function ReadArray(i : integer):boolean;
  procedure WriteArray(i : integer; val:boolean);
public
  property ID       : integer read FID        write FID;
  property LastName : string  read FLastName  write FLastName;
  property FirstName: string  read FFirstName write FFirstName;
  property Email    : string  read FEmail     write FEmail;
  property MyArray[i : integer] :boolean read ReadArray write WriteArray;
end;

Example

  person := TPerson.create();
  person.ID := 25;
  person.FirstName := 'Homer';
  person.LastName  := 'Bologna';
  person.Email := 'Homer@Bologna.com';

  person.myArray[0] := true;
  person.myArray[1] := false;
  person.myArray[2] := true;

  str := TJson.ObjectToJsonString(person);//Access Violation

Solution

  • You can persuade ObjectToJsonString to handle arrays, but they need to be arrays with type info. Your array uses an inline type, and they do not have type info.

    For instance declare the field fMyArray like this:

    type
      TPerson = class(TObject)
      private
        type
          TBooleanArray = array [0 .. 2] of Boolean;
      private
        FID: integer;
        FLastName: string;
        FFirstName: string;
        FEmail: string;
        fMyArray: TBooleanArray; // <-- this type has type info
    
        function ReadArray(i: integer): Boolean;
        procedure WriteArray(i: integer; val: Boolean);
      public
        property ID: integer read FID write FID;
        property LastName: string read FLastName write FLastName;
        property FirstName: string read FFirstName write FFirstName;
        property Email: string read FEmail write FEmail;
        property MyArray[i: integer]: Boolean read ReadArray write WriteArray;
      end;
    

    A call to ObjectToJsonString produces this:

    {"iD":0,"lastName":"","firstName":"","email":"","myArray":[false,false,false]}
    

    Likewise, for dynamic arrays use

    fMyArray: TArray<Boolean>;
    

    rather than

    fMyArray: array of Boolean;
    

    for the exact same reason.

    You might want to consider using a different JSON library though. The Embarcadero supplied library doesn't have the best of reputations.