AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Thema durchsuchen
Ansicht
Themen-Optionen

Problem bei JSON-Abfrage

Ein Thema von Maekkelrajter · begonnen am 20. Sep 2020 · letzter Beitrag vom 4. Nov 2020
Antwort Antwort
Seite 2 von 2     12   
Maekkelrajter

Registriert seit: 8. Mär 2017
Ort: Köln
156 Beiträge
 
Delphi 12 Athens
 
#11

AW: Problem bei JSON-Abfrage

  Alt 23. Sep 2020, 12:04
Seit ein paar Tagen versuche ich, eine Abfrage nach Uwe Raabes Vorschlag zu realisieren. Bei der Ausführung der ' GetPlaylistTracks' - Funktion allerdings flogen mir die AccessViolations nur so um die Ohren
Den 'Unfallort' konnte ich in der Procedure TJSONUnMarshal.PopulateFields in der Unit REST.JsonReflect ausmachen:
Delphi-Quellcode:
procedure TJSONUnMarshal.PopulateFields(JsonFields: TJSONObject; Data: TObject;
  JsonCustomizer: TJSONPopulationCustomizer);

[...]

        else if jsonFieldVal is TJSONArray then
        begin
          rField := GetFieldType(Data, FieldName);
          // Unmarshal TList<T>.FListHelper as dynamic array using 10.2 layout
          if (rField.FieldType.Handle = TypeInfo(System.Generics.Collections.TListHelper)) and // Hier kracht's, wenn rField = NIL
             (I < JsonFields.Count - 1) and
             (string.CompareText('listHelper', FieldName) = 0) and
             (string.CompareText('items', JsonFields.Pairs[I + 1].JsonString.Value) = 0) then
          begin
            // "listHelper":[2] - ignore
            Inc(I);
            // "items":[{},{}]
            jsonFieldVal := JsonFields.Pairs[I].JsonValue;
            LValue := rField.GetValue(Data); // Get FListHelper
            SetTListHelperValueFromArrayValue(FRTTICtx, LValue,
              function (AArrType: TRttiType): TValue
              begin
                Result := JSONToTValue(jsonFieldVal, AArrType);
              end);
            rField.SetValue(Data, LValue); // Set FListHelper
          end
          else
            SetFieldArray(Data, FieldName, TJSONArray(jsonFieldVal));
        end
Immer dann, wenn ein Array nicht deklariert ist, gibt GetFieldType(Data, FieldName) NIL zurück, worauf prompt eine AccessViolation - Exception folgt. In unserem Fall waren das die Arrays 'images' und 'available_markets'.
Deshalb habe ich nun versucht, diese in die Typ-Deklarationen einzufügen. Bei 'images' ist mir das gelungen, nicht jedoch bei 'available_markets', was laut Spotify Web API Dokumentation als 'Array of Strings' deklariert ist.
Delphi-Quellcode:
  
// Von mir hinzugefügt:
TImage = class
  private
    FHeight: Integer;
    FWidth: Integer;
    FUrl: String;
  public
    property height: Integer read FHeight;
    property width: Integer read FWidth;
    property URL: String read FUrl;
  end;


  TAlbum = class
  private
    FArtists: TArray<TArtist>;
    FMarkets: TArray<String>;
    FName: string;
  public
    property Artists: TArray<TArtist> read FArtists;
    property available_markets: TArray<string> read FMarkets; // funktioniert nicht
    property Name: string read FName;
  end;

  TTrack = class
  private
    FAlbum: TAlbum;
    FArtists: TArray<TArtist>;
    FId: string;
    FName: string;
    FMarkets: TArray<String>;
  public
    property Album: TAlbum read FAlbum;
    property Artists: TArray<TArtist> read FArtists;
    property Id: string read FId;
    property Name: string read FName;
    property available_markets: TArray<String> read FMarkets; // funktioniert nicht

   [...]

  TPlayList = class
  private
    FName: string;
    FImages: TArray<TImage>;
    FTracks: TPaging<TPlaylistTrack>;
  public
    property Name: string read FName;
    property Images: TArray<TImage> read FImages; //das funktioniert!
    property Tracks: TPaging<TPlaylistTrack> read FTracks;
  end;
Was mache ich bei der Deklaration falsch?
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.447 Beiträge
 
Delphi 12 Athens
 
#12

AW: Problem bei JSON-Abfrage

  Alt 23. Sep 2020, 15:24
Wenn der JSON-Value available_markets heisst, dann muss auch das Feld FAvailable_markets heißen. Delphi geht nach den Feldern, nicht nach den Properties. Die Regel ist: F entfernen, den dann ersten Buchstaben klein schreiben

Alternativ kann man den Namen auch mit einem Attribut überschreiben:
Delphi-Quellcode:
  TAlbum = class
  private
    FArtists: TArray<TArtist>;
    [JSONName('available_markets')]
    FMarkets: TArray<String>;
    FName: string;
  public
    property Artists: TArray<TArtist> read FArtists;
    property Markets: TArray<string> read FMarkets;
    property Name: string read FName;
  end;
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Maekkelrajter

Registriert seit: 8. Mär 2017
Ort: Köln
156 Beiträge
 
Delphi 12 Athens
 
#13

AW: Problem bei JSON-Abfrage

  Alt 23. Sep 2020, 23:02
So funktioniert's tatsächlich. Naja, das muss man natürlich wissen. Ich war eben davon ausgegangen, dass die Properties die Schnittstelle einer Klasse sind.
Dass aber ein Funktionsrückgabewert innerhalb einer Methode nicht auf Gültigkeit überprüft wird und eine Accessviolation auslöst, kann man doch nur als Bug ansehen. Ein ähnlicher Fall lag ja auch meinem Ausgangs-Posting in diesem Thread zugrunde. Dem Vernehmen nach sind ja die JSON-Bibliotheken unter Delphi 10.3 als fehlerbehaftet berüchtigt. Da kann ich nur hoffen, dass die Version 10.4 da ausgereifter ist. Aber leider ist die ja (noch) nicht als Community-Edition verfügbar. Oder habe ich da was verpasst?

Gruß LP
  Mit Zitat antworten Zitat
Maekkelrajter

Registriert seit: 8. Mär 2017
Ort: Köln
156 Beiträge
 
Delphi 12 Athens
 
#14

AW: Problem bei JSON-Abfrage

  Alt 26. Sep 2020, 18:16
Nachdem das Ganze prinzipiell funktionierte, tauchte prompt die nächste Hürde auf. Die Spotify Web API limitiert nämlich die Zugriffe bei einer Playlist auf 100 Einträge. Ist die Liste länger, müssen weitere 'Seiten' des Paging-Objects nachgeladen und eingelesen werden. Die Frage war also, wie die weiteren Tracks dem Playlist-Objekt, soll heißen dem Array TPlaylist.Tracks.Items hinzugefügt werden können. Ich wollte nämlich keine zusätzliche 'externe' Liste für die Einträge anlegen, sondern nach Verlassen der Prozedur 'GetPlaylistTracks' sollte das Objekt 'Playlist' den kompletten Baum des von Spotify gelieferten Playlist-Objekts zur weiteren universellen Verwendung enthalten. Anderenfalls hätte man sich den ganzen Aufwand auch sparen können. Nach vielen Stunden mühsamer Recherche und viel Try & Error habe ich folgende Lösung gefunden:
Delphi-Quellcode:
Function TSpManager.SendRequest(accesspoint:string; offset: Integer = 0; Limit: Integer = 50):TJSONValue;
begin
  result:= NIL;
  If FAuthorized Then
  begin
    RESTRequest1.Params.ParameterByName('offset').Value:= offset.ToString;
    RESTRequest1.Params.ParameterByName('limit').Value:= limit.ToString;
    RESTRequest1.Resource:= AccessPoint;
    RestRequest1.Execute;
    result:= RestResponse1.JSONValue;
  end else If NoSpotifyAccessMsg = mrYes Then AuthorizespotifyAccess;
end;


function TSpManager.GetPlaylistTracks(var Playlist: TPlaylist; PlaylistID: string): Boolean; //komplette Playlist-Daten holen
var
  JValue,oitem: TJSONValue;
  oItems: TJSONArray;
  newitem: TPlaylisttrack;
  offs,nextpos,totalItems: Integer;
begin
  result := false;
  offs:= 0;
  JValue:= SendRequest('v1/playlists/' + PlaylistID);
  if JValue is TJSONObject then
  begin
    playlist := TJson.JsonToObject<TPlaylist>(TJSONObject(JValue));
    if playlist <> nil then
    begin
      totalItems:= playlist.Tracks.total;
      offs:= length(playlist.Tracks.Items);
      while offs < TotalItems do // nächste 'Seite' des Paging-Objects
      begin
        Jvalue:= SendRequest('v1/playlists/' + PlaylistID + '/tracks',offs,100);
        If JValue is TJSONObject Then
        begin
          oItems := TJSONArray(TJSONObject(JValue).GetValue('items'));
         // Erweitert das Array Playlist.Tracks.Items um oItems.count und liefert die bisherige Größe als Offset zurück:
          nextpos:= playlist.IncreaseItems(oitems.count);
          for oItem in oItems do
          begin
            newitem:= TJson.JsonToObject<TPlaylisttrack>(TJSONObject(oitem));
            playlist.SetItem(newitem,nextpos); // schreibt newitem in das Array
            inc(nextpos);
          end;
        end;
        inc(offs, oitems.Count);
      end;
    end;
  end;
  result:= playlist <> NIL;
end;
Das funktioniert auch perfekt, und sogar die Performance (incl. Ladevorgang) ist akzeptabel. Aber wie immer, wenn ich so etwas zusammen gefrickelt habe, kommt die Frage auf, ob diese Lösung wirklich 'State of The Art' ist und es nicht womöglich effizienter und/oder eleganter geht


Gruß LP
Miniaturansicht angehängter Grafiken
webapiscreenshot.jpg  
  Mit Zitat antworten Zitat
Maekkelrajter

Registriert seit: 8. Mär 2017
Ort: Köln
156 Beiträge
 
Delphi 12 Athens
 
#15

AW: Problem bei JSON-Abfrage

  Alt 4. Nov 2020, 11:55
Dass aber ein Funktionsrückgabewert innerhalb einer Methode nicht auf Gültigkeit überprüft wird und eine Accessviolation auslöst, kann man doch nur als Bug ansehen.
Gruß LP
Nachtrag:
Dieser Bug in der Version 10.3.2 wurde schon in der Version 10.3.3 behoben.
Auf meinem Windows7 - System, auf dem ich dieses Projekt bisher entwickelt habe, läuft leider nur 10.3.2, so dass ich mich noch mit dem Bug herumschlagen musste.
Auf meinem Win10 - System läuft sowohl die IDE als auch mein Programm unter 10.3.3 fehlerfrei: Nicht deklarierte Arrays werden einfach ignoriert und lösen keine Exception mehr aus. Geht doch!

Gruß LP
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 00:30 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz