1

I'm attempting to deserialize a JSON response from a web service. The response is in the form of an array of well-typed objects. As an example, I'm using songster.com.

In the following (excerpted) code, clearly TSongsterResponse is not correct, since I'm getting a collection back. But neither array of TSongsterResponse nor TSongsterList will compile.

interface

type
  TSongsterResponse = class
    public
      id: integer;
      title: string;
  end;

type TSongsterList = array of TSongsterResponse;

implementation

procedure Sample(AJson: string);
begin
  // What goes here to get an array of TSongsterResponse?
  FSomething :=   TJson.JsonToObject<?????>(RESTResponse1.Content);
end;
2
  • @RemyLebeau I tried to follow that example, but I'm hoping to get a typed object from each array value, and that example is extracting a string value from a generic TJsonObject. I can't see how to modify the inner loop to produce a TSongsterResponse for each array item. Commented Oct 12, 2021 at 18:46
  • see the answer I just posted Commented Oct 12, 2021 at 19:58

1 Answer 1

2

TJson.JsonToObject(), as its name suggests, requires an object type, not an array type. It has a Generic constraint of class, constructor, which means it must be able to Create an object to deserialize into. It can't deserialize a JSON array that is not inside of a JSON object.

You might try wrapping RESTResponse1.Content with '{...}', otherwise you will likely just have to resort to using TJSONObject.ParseJSONValue() instead and build up the TSongsterList manually yourself (see Delphi parse JSON array or array).

It would help to see the actual JSON being parsed, but there is nothing stopping you from defining your own class types to copy the JSON values into. For example:

interface

type
  TSongsterResponse = class
  public
    id: integer;
    title: string;
  end;

  TSongsterList = array of TSongsterResponse;

implementation

uses
  System.JSON;

var
  FSomething: TSongsterList;

procedure Sample(AJson: string);
var
  Value: TJSONValue;
  Arr: TJSONArray;
  Obj: TJSONObject;
  Song: TSongsterResponse;
  I: Integer;
begin
  Value := TJSONObject.ParseJSONValue(AJson);
  if Value = nil then Exit;
  try
    Arr := Value as TJSONArray;
    SetLength(FSomething, Arr.Count);
    for I := 0 to Arr.Count-1 do
    begin
      Obj := Arr[I] as TJSONObject;
      Song := TSongsterResponse.Create;
      try
        Song.id := (Obj.GetValue('id') as TJSONNumber).AsInt;
        Song.title := Obj.GetValue('title').Value;
        FSomething[I] := Song;
      except
        Song.Free;
        raise;
      end;
    end;
  finally
    Value.Free;
  end;
  // use FSomething as needed...
end;
...
Sample(RESTResponse1.Content);

That being said, do note that TRESTResponse has a JSONValue property that can parse the received JSON content for you, eg:

interface

type
  TSongsterResponse = class
  public
    id: integer;
    title: string;
  end;

  TSongsterList = array of TSongsterResponse;

implementation

uses
  System.JSON;

var
  FSomething: TSongsterList;

procedure Sample(AJson: TJSONValue);
var
  Arr: TJSONArray;
  ...
begin
  Arr := AJson as TJSONArray;
  // process Arr same as above...
  // use FSomething as needed...
end;
...
Sample(RESTResponse1.JSONValue);
Sign up to request clarification or add additional context in comments.

1 Comment

Why was this answer not accepted? Doing so makes it clear to others that it works (it's Remy, so of course it works).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.