Why TJson.ObjectToJsonObject/ObjectToJsonString represents record fields as a JSON array?

2.3k views Asked by At

There is an inconsistency of how SuperObject and TJson.ObjectToJsonObject represent certain parts of a class (i.e. Record fields). Let's have the following code snippet:

Uses rest.json, superobject;

  type

      TSimplePersonRec = record
        FirstName: string;
        LastName: string;
        Age: byte;
      end;

      TSimplePerson = class
        protected
          FPersonRec: TSimplePersonRec;
        public
          property personRecord: TSimplePersonRec read FPersonRec write FPersonRec;
      end;

    // ...

        { Public declarations }
        function toJson_SO(simplePerson: TSimplePerson): string;
        function toJson_Delphi(simplePerson: TSimplePerson): string;

    // ...

    function TForm1.toJson_Delphi(simplePerson: TSimplePerson): string;
    begin
      result := tjson.Format(TJson.ObjectToJsonObject(simplePerson));
    end;

    function TForm1.toJson_SO(simplePerson: TSimplePerson): string;
    var
      so: ISuperObject;
      ctx: TSuperRttiContext;
    begin
      ctx := TSuperRttiContext.Create;
      try
        so := ctx.AsJson<TSimplePerson>( simplePerson );
      finally
        ctx.Free;
      end;
      result := so.AsJSon(true, true);
    end;

    // ...

    procedure TForm1.Button3Click(Sender: TObject);
    var
      spr: TSimplePersonRec;
      sp: TSimplePerson;
    begin

      spr.FirstName := 'John';
      spr.LastName := 'Doe';
      spr.Age := 39;

      sp := TSimplePerson.Create;
      sp.personRecord := spr;

      memo1.Lines.Add(#13'--- SuperObject ---'#13);
      memo1.Lines.Add(toJson_SO(sp));
      memo1.Lines.Add(#13'---   Delphi    ---'#13);
      memo1.Lines.Add(toJson_Delphi(sp));
    end;

The OUTPUT is:

--- SuperObject ---
{
 "FPersonRec": {
  "LastName": "Doe",
  "Age": 39,
  "FirstName": "John"
 }
}
---   Delphi    ---
{
  "personRec":
  [
    "John",
    "Doe",
    39
  ]
}

What's the reason for Delphi to represent records as JSON array? Is there a public standard or suggestion leading to this?

Note: For me it's more natural to represent records with {key: value} notation instead of array. Not knowing the key name to witch the value belongs may have strange results during deserialization. For Example during deserialization I could pass a new class with the same layout, containing a record with different memory layout. In this case the values will be randomly assigned or an AV could occur?

UPDATE: I'm using Delphi XE7. Also I found this of json.org:

JSON is built on two structures:

  • A collection of name/value pairs. In various languages, this is realized as an object, record, struct, dictionary, hash table, keyed list, or associative array.
  • An ordered list of values. In most languages, this is realized as an array, vector, list, or sequence.

So probably the question is more about is this a bug in TJson unit?

1

There are 1 answers

1
Remy Lebeau On

The Delphi output is legal JSON. Internally, REST.TJson is hard-coded to marshal a record as a JSON array. That is simply how it is implemented, it is by design, not a bug. It is just another way to represent data. SuperObject chooses to be more explicit. That is also OK. Two different implementations, two different representations. The JSON spec allows for both.