IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Delphi Discussion :

[REST/JSON] Pourquoi un Transtypage erreur


Sujet :

Delphi

  1. #1
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    2 004
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 2 004
    Points : 6 281
    Points
    6 281
    Par défaut [REST/JSON] Pourquoi un Transtypage erreur
    Bonjour aux Delphistes

    J'essaie d'extraire les données d'une réponse REST avec Delphi 10.3.3.

    Je veux récupérer dans une variable string une valeur "JSONobject.value" qui est un string et j'obtiens une erreur "Transtypage de classe incorrect".

    J'avoue ne pas avoir la moindre expérience avec JSON...Ou est-ce que je me plante?

    J'ai comme réponse JSON en lisant le string "RESTResponse1.JSONText":

    [
    {
    "header": "2;20200904 2;OUT;4;",
    "comment": null,
    "data": "21;1;074170382839;22;1;095008026503;",
    "status": -4,
    "statusmsg": "DOCS: doc_status is not valid"
    }
    ]
    Et mon code qui finit par l'erreur de transtypage est:

    RESTRequest1.Execute;
    objJson := RESTResponse1.JSONValue as TJSONObject;
    str:= objJson.Values['data'].Value;
    Mais le problème ne vient pas de la ligne "str:=...", j'ai le message d'erreur sur "objJson := RESTResponse1.JSONValue as TJSONObject;" avec la variable "objJson : TJSONObject;"

  2. #2
    Rédacteur/Modérateur

    Avatar de SergioMaster
    Homme Profil pro
    Développeur informatique retraité
    Inscrit en
    Janvier 2007
    Messages
    15 163
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 68
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations professionnelles :
    Activité : Développeur informatique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Janvier 2007
    Messages : 15 163
    Points : 41 346
    Points
    41 346
    Billets dans le blog
    63
    Par défaut
    Bonjour,

    rapidement j'aurai mis un toString
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    str:= objJson.Values['data'].Value.ToString;
    mais je n'ai pas vraiment l'habitude de passer par des Objets JSON non plus me contentant d'utiliser RESTDebugger qui me produit les composants nécessaires

  3. #3
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    je ne connais pas JSONObject...mais cette réponse JSON est un array [] qui contient un seul objet {} donc ton code est forcément faux puisque tu cherches à lire un objet au lieu d'un tableau d'objets

  4. #4
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    2 004
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 2 004
    Points : 6 281
    Points
    6 281
    Par défaut
    Citation Envoyé par SergioMaster Voir le message
    Bonjour,

    rapidement j'aurai mis un toString
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    str:= objJson.Values['data'].Value.ToString;
    mais je n'ai pas vraiment l'habitude de passer par des Objets JSON non plus me contentant d'utiliser RESTDebugger qui me produit les composants nécessaires
    Jusqu'à maintenant, j'utilisais également REST sans utiliser JSON mais j'ai été confronté à une limite imprévue qui est bonne à savoir donc j'en parle ici...

    Pour résumer, ma réponse REST était envoyée dans un clientdataset et je récupérais les données par des "str:=ClientDataset1.FieldValues['data'];"... mais avec cette approche ton string "data" est limité à... 255 caractères!

    D'où ma quête dans les méandres de l'usage de REST/JSON

  5. #5
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    2 004
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 2 004
    Points : 6 281
    Points
    6 281
    Par défaut
    Citation Envoyé par Paul TOTH Voir le message
    je ne connais pas JSONObject...mais cette réponse JSON est un array [] qui contient un seul objet {} donc ton code est forcément faux puisque tu cherches à lire un objet au lieu d'un tableau d'objets
    Tu a raison mais le problème se déclenche avant d'avoir à traiter l'aspect tableau...

    Mon code se base sur un code "vendu" comme fonctionnel qui avait la forme suivante:

    objJson := RESTResponse1.JSONValue as TJSONObject;
    dataJson := objJson.Values['header'] as TJSONObject;
    str:= dataJson.Values['data'].Value;
    Donc on récupère le tableau dans"obJson" (et là j'ai l'erreur de transtypage), on récupère dans "objson" l'objet "datajson" et ensuite on récupère la valeur "header" de "datajson".

    Ce code est vieux de 4 ans. Peut-être qu'il fonctionnait sur les anciennes versions de Delphi...

  6. #6
    Membre expert
    Avatar de pprem
    Homme Profil pro
    MVP Embarcadero - formateur&développeur Delphi, PHP et JS
    Inscrit en
    Juin 2013
    Messages
    1 876
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Loiret (Centre)

    Informations professionnelles :
    Activité : MVP Embarcadero - formateur&développeur Delphi, PHP et JS
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Juin 2013
    Messages : 1 876
    Points : 3 614
    Points
    3 614
    Par défaut
    m'intrigue : tout dans TJSONxxx retourne des TJSONValues, donc dans la ligne récupérant la chaine, j'aurais trans type en TJSONString avant d'en récupérer le values. à vérifier

  7. #7
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    2 004
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 2 004
    Points : 6 281
    Points
    6 281
    Par défaut
    Delphi 10.3.3 est livré avec un exemple utilisant REST et json: RESTDemos

    Je compile le projet qui propose différents exemples d'utilisation de REST, ils fonctionnent sauf l'exemple utilisant JSON qui se termine en erreur.

    Je reprends le code et l'insère dans mon application

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    var
      LValues: TJSONArray;
      LJson: TJSONObject;
      LTempSensorName: string;
      LValue: TJsonValue;
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
      LJson := RESTRequest.Response.JSONValue as TJSONObject;
      LValues := LJson.Values['values'] as TJSONArray;
      for LValue in LValues do
      begin
        // the sensor values are not objects unfortunately, but arrays of strings
        if (LValue as TJSONArray).Items[0].Value = LTempSensorName then
        begin
          LTemp := StrToInt((LValue as TJSONArray).Items[1].Value) / 100;
          Lbl_Temperature.Caption := Format('%3.0f°F', [LTemp]);
          break;
        end;
      end;
    Et cela se termine par un "Transtypage erreur" sur la première ligne "LJson := RESTRequest.Response.JSONValue as TJSONObject;"

    Je ne peux même pas récupérer la réponse REST dans une variable de type TJSONObject sous la forme d'un TJSONObject !!!

    Cela laisse songeur...

  8. #8
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    il faudrait faire du pas à pas dans RESTRequest.Response.JSONValue car tu as probablement une réponse à nil et l'exception indique que nil n'est pas un TJSONObject

    ou au minimum voir l'exception en mode debug car, s'il y en a une, est masquée

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    function TCustomRESTResponse.GetJSONValue: TJsonValue;
    var
      LTemp: Boolean;
    begin
      Result := nil;
      if Content <> '' then
        try
          GetJSONResponse(Result, LTemp);
        except
          // This method ignores exceptions
        end;
    end;

  9. #9
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    2 004
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 2 004
    Points : 6 281
    Points
    6 281
    Par défaut
    Le problème semble avoir pour origine que le format du JSON envoyé par le serveur n'est pas compatible avec le "JSON made in Delphi"!

    J'ai trouvé un exemple qui fonctionne avec code et "JSON qui convient" et le JSON comporte des "\" que je n'ai vu dans aucun exemple de fichier JSON

    const
    response =
    '{"result":["[{\"email\":\"XXX@gmail.com\",\"regid\":\"12312312312312312313213w\"},'+
    '{\"email\":\"YYYY@gmail.com\",\"regid\":\"AAAAAAA\"}]"]}';

    response_bis =
    '{"result":["[{"email":"XXX@gmail.com","regid":"12312312312312312313213w"},'+
    '{"email":"YYYY@gmail.com","regid":"AAAAAAA"}]"]}';

    var
    LResult: TJSONArray;
    LJsonResponse: TJSONObject;
    ja: TJSONArray;
    jv: TJSONValue;

    begin

    LJsonResponse := TJSONObject.ParseJSONValue(response) as TJSONObject;
    LResult := LJsonResponse.GetValue('result') as TJSONArray;
    ja := TJSONObject.ParseJSONValue(LResult.Items[0].Value) as TJSONArray;
    for jv in ja do begin
    memo1.Lines.Add(jv.GetValue<string>('email'));
    memo1.Lines.Add(jv.GetValue<string>('regid'));
    end;
    end;
    Le même code traitant un JSON provenant de différents serveurs de test via REST donne un "Transtypage erreur" sur la ligne "LJsonResponse := TJSONObject.ParseJSONValue(response) as TJSONObject;"

    Le même code avec le "JSON qui convient" sans les "\" (=response_bis) et on se retrouve avec un "Violation d'accès"...

    Je me demande s'il ne faut pas tout simplement oublier le traitement JSON via les fonctions fournies par Delphi!

  10. #10
    Expert éminent sénior
    Avatar de Paul TOTH
    Homme Profil pro
    Freelance
    Inscrit en
    Novembre 2002
    Messages
    8 964
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 55
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Freelance
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Novembre 2002
    Messages : 8 964
    Points : 28 457
    Points
    28 457
    Par défaut
    Citation Envoyé par Anselme45 Voir le message
    Le problème semble avoir pour origine que le format du JSON envoyé par le serveur n'est pas compatible avec le "JSON made in Delphi"!
    JSON c'est un format normalisé, il n'y a pas de "JSON made in Delphi", au pire tu as un bug dans le Parser JSON de Delphi.

    Citation Envoyé par Anselme45 Voir le message
    J'ai trouvé un exemple qui fonctionne avec code et "JSON qui convient" et le JSON comporte des "\" que je n'ai vu dans aucun exemple de fichier JSON
    response_bis est invalide pour moi...response est valide mais étrange, c'est une liste de chaînes qui sont au format JSON...c'est possible mais je ne vois pas l'intérêt de mettre du JSON dans du JSON.

    dans la notation suivante

    {"result":[]}

    tu indique que result est un tableau

    sauf que le premier caractère qui suis le [ c'est un ", c'est donc une chaîne qui est

    "[{\"email\":\"XXX@gmail.com\",\"regid\":\"12312312312312312313213w\"},{\"email\":\"YYYY@gmail.com\",\"regid\":\"AAAAAAA\"}]"

    c'est donc une chaîne qui contient du JSON qui une fois json-décodée donne

    [{"email":"xxx@mail.com","regid":"12312312312312312313213w"},{"email":"YYYY@gmail.com","regid":"AAAAAAA"}]

    soit une liste de deux objets comprenant les champ email et regid.

    dans response_bis tu as une chaîne "[{" suivi de 'email..." qui n'a aucun sens

    {"result":["[{"email":"XXX@gmail.com","regid":"12312312312312312313213w"},{"email":"YYYY@gmail.com","regid":"AAAAAAA"}]"]}';

    le bon format devrait être

    {"result":[{"email":"xxx@mail.com","regid":"12312312312312312313213w"},{"email":"YYYY@gmail.com","regid":"AAAAAAA"}]}

  11. #11
    Membre extrêmement actif
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Octobre 2017
    Messages
    2 004
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Suisse

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Octobre 2017
    Messages : 2 004
    Points : 6 281
    Points
    6 281
    Par défaut
    Je fais profiter les Delphistes de la solution ("bricolage" serait un meilleur terme) que j'ai trouvé pour résoudre mon problème de Transtyping error.

    Je confirme que le problème provient du format de la réponse JSON envoyée par le serveur. Il y a apparemment JSON et JSON pour certains Le JSON retrourné n'a pas un format "{"result":[...]}" mais "{[...]}".

    Solution:

    1. Je récupère le JSON envoyé par le serveur par un "str:=RESTResponse1.JSONText;"

    2. J'adapte le string: "{[...]}" devient "{"result":[...]}"

    3. Je transforme le string modifié en un TJSONValue par un "JSONValue := TJSonObject.ParseJSONValue(str);" (Eureka! il n'y a plus de "Transtyping error")

    4. Je récupère les valeurs dans JSONValue par du code du genre "str1 := JsonValue.GetValue<string>('results[0].header');"


    Merci aux divers intervenants qui m'ont proposé leur aide.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [EJB / REST / JSON / JQuery] Problème pour faire un POST
    Par saveriu dans le forum Services Web
    Réponses: 1
    Dernier message: 19/04/2012, 11h08
  2. REstFul Json à JSONP
    Par topolino dans le forum Windows Communication Foundation
    Réponses: 0
    Dernier message: 20/03/2012, 09h00
  3. REST JSON et post
    Par topolino dans le forum Windows Communication Foundation
    Réponses: 4
    Dernier message: 28/03/2011, 17h40
  4. Réponses: 1
    Dernier message: 18/04/2008, 04h33

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo