1

I am trying to convert Json trying to class object, but the values are not appearing in the new object variable. The resulting object has blank value in string and 0 in integer. Thanks in advance.

Code:

type
Student =class
    public
    Name : string;
    Age : Integer;
end;

procedure TForm2.Button5Click(Sender: TObject);
var
  Student1, Student2: Student;
  STR: string;
begin
  Student1 := Student.Create;
  Student2 := Student.Create;

  try
  Student1.Name := 'Sam';
  Student1.Age := 24;
  str := TJson.ObjectToJsonString(Student1);
  Form2.outputMemo.Lines.Add(str);
  Student2 := TJSON.JsonToObject<Student>(str);
  Form2.outputMemo.Lines.Add(Student2.Name);
  Form2.outputMemo.Lines.Add(Student2.Age.ToString);
  finally
  Student1.Free;
  Student2.Free;
  end;
//Form2.outputMemo.Lines.Text :=TJson.ObjectToJsonObject(Student1);

end;

Output:

{"name":"Sam","age":24}

0

Edit: I just saw this, and it worked when I changed the names to FName and FAge... what a sorcery!, can anyone please explain the logic behind this? Delphi Rest.JSON JsonToObject only works with f variables

S. B.
  • 186
  • 1
  • 12
  • Why are you using classes rather than records for your data persistence? – David Heffernan Mar 27 '22 at 08:44
  • 1
    @DavidHeffernan, perhaps because there is no built-in conversion for records as there is with TJSON for classes. – Uwe Raabe Mar 27 '22 at 08:54
  • BTW, there is a memory leak from `Student2 := Student.Create`, as `Student2` is assigned later with `TJSON.JsonToObject`, leaving the former instance in memory. – Uwe Raabe Mar 27 '22 at 08:57
  • @Uwe wow that's crazy! – David Heffernan Mar 27 '22 at 09:03
  • @DavidHeffernan, I am new to Delphi, in C# we usually use data classes, if there is any other way to do it efficiently, please suggest the same. But I do need to convert the objects to JSON and vice versa here. – S. B. Mar 27 '22 at 09:14
  • @UweRaabe, what can be done to avoid this? Shall I use `Student1.Free` before assigning Student2? As I said I am very new to Delphi, please suggest if I am doing it wrong. Also this is just a practice example to understand. In my real code I will be calling `Post().ContentAsString()` and convert that to class object. – S. B. Mar 27 '22 at 09:17
  • There are lots of ways to work with json. But you look like you have data only structures here and surely they are a better fit for records. But we don't have much context to advise you. – David Heffernan Mar 27 '22 at 09:44
  • 1
    Don't create `Student2` in the first place. It would be sufficient to initialize it with `nil`. – Uwe Raabe Mar 27 '22 at 13:24
  • @UweRaabe, Okay thanks! so removing the line `Student2 := Student.Create;` will be enough right? or do I need to specify `Student2 := nil;`? – S. B. Mar 27 '22 at 13:28
  • 1
    As long as `Student2` is a local variable of the current method an initialization with `nil` is recommended. Otherwise the content is arbitrary and in case of an error before the assignment with `TJSON.JsonToObject` (which can happen during the conversion), the call to `Student2.Free` may use uninitialized memory. – Uwe Raabe Mar 27 '22 at 13:33
  • 1
    @DavidHeffernan, in theory I would agree with you, but while records may serve well for flat structures like shown in the question, JSON is usually made of hierarchies of objects (the "O" in JSON). I have found that it is easier to use classes in all cases than to have a different record approach in only some cases where it may accidentally fit. It happens all too often that a flat record-like structure soon evolves to a complex hierarchy. Starting with classes right away significantly reduces the stress when this happens. – Uwe Raabe Mar 27 '22 at 13:43
  • @uwe json has scalars, arrays and objects. Arrays can map to dynamic arrays and objects to records. – David Heffernan Mar 27 '22 at 15:35

1 Answers1

4

The internal mapping of JSON fields to Delphi fields is prefixing them with F and changing the following character to upper case. If you want complete control over this you can specify the JSON name with an attribute:

type
  Student =class
  public
    [JSONName('name')]
    Name : string;
    [JSONName('age')] 
    Age : Integer;
  end;

Note that the JSON names given are case sensitive.

You need to include REST.Json.Types to the uses so that the attribute declaration can be found.

Uwe Raabe
  • 45,288
  • 3
  • 82
  • 130
  • Thanks for your answer, but currently I'll keep them as FFieldName, I have huge class, it will be very time consuming. – S. B. Mar 27 '22 at 09:19
  • 1
    If you aren't yet, definitely try out MMX (https://www.mmx-delphi.de/). It makes adding properties with private fields very easy and fast – RaelB Mar 27 '22 at 18:45