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

Java Discussion :

Aspect selon valeur retournée


Sujet :

Java

  1. #1
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 734
    Par défaut Aspect selon valeur retournée
    Bonjour.

    J'ai une application qui fait appel à une API externe PersonAPI de cette façon :
    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public void modifierPersonne() {
        //Traider input
        PersonDto output = personApi.modify(input);
        //Traiter output
    }
    public void creerPersonne() {
        //Traider input
        PersonDto output = personApi.create(input);
        //Traiter output
    }

    L'API retourne ce genre de JSON :
    Code JSON : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    {
        code: 200,
        messages: [],
        data: {
            person: {name: "name", age: 100, ...}
        }
    }

    Problème, la gestion des erreurs est mal conçue et l'API peut retourner un code HTTP 200 avec des données tel que :
    Code JSON : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {
        code: 400,
        messages: [
            severity: "ERROR",
            content: "Invalid character in 'name'"
        ],
        data: {
            person: {name: "א", age: 100, ...}
        }
    }

    Ce comportement ne pouvant pas changer, je souhaite m'adapter, mais si possible sans toucher au code existant (base de code assez grande).
    Les Aspects semblent être une bonne solution, j'en utilise déjà pour log des appels de fonctions très précises.
    Je pense intercepter les données de retour et envoyer une exception si le champ severity est "ERROR".

    Je voudrais savoir si il est possible d'intercepter le processus juste après que la fonction ait retourné le JSON (retour de personApi.create()) mais avant que la valeur soit assignée à p output ?
    Sinon si il y existe une option plus pertinente ?
    :hola: Je fais appel aux esprits de Ritchie, Kernighan, Stroustrup et Alexandrescu :hola:
    Donnez moi la force, donnez moi le courage de coder proprement !

  2. #2
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    Hello,

    il est pas clair quels sont les partis en présence.

    Qu'est-ce qui est un programme serveur d'API qui tourne quelque part dans le monde, et qu'est-ce qui est un programme qui appelle cette API ? Y a-t-il d'autres programmes ? Quel est le programme que tu as besoin de modifier ? Les bouts de code que tu as montré font partie de quel programme ?

    C'est quoi, p ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 734
    Par défaut
    L'API est est une API REST qui tourne sur un serveur, qui se matérialise dans le code par le service personApi.

    J'aimerais modifier mon programme, mais si possible sans toucher au code que j'ai présenté.

    p est un mauvais-copier-coller, c'est output.
    :hola: Je fais appel aux esprits de Ritchie, Kernighan, Stroustrup et Alexandrescu :hola:
    Donnez moi la force, donnez moi le courage de coder proprement !

  4. #4
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    ?

    Bah. Peut-être et peut-être pas. Si tu as déjà utilisé des aspects tu dois avoir une idée de comment ça marche n'est-ce pas ?

    Alors comment diable quelqu'un qui n'est pas toi, pourrait-il avoir la moindre idée de si c'est possible, avec ce que tu nous montres ? Je trouve étrange qu'il y ait besoin de te dire ça, sans que ça te paraisse évident dès le départ.

    Je veux dire, que ce soit possible, c'est pratiquement garanti, surtout qu'il existe des moyens de coller des aspects sur les méthodes privées. Difficile d'imaginer que la manière dont personApi matérialise l'API ne rende pas ça possible d'une manière ou d'une autre.

    Mais concernant comment s'y prendre en pratique, il faut bien entendu regarder de quelle manière exacte cette API est matérialisée, bref il faut regarder exactement ce que tu ne montres pas. Et c'est assez surprenant que ça ne t'ait pas sauté aux yeux je dois dire.

    Je voudrais savoir si il est possible d'intercepter le processus juste après que la fonction ait retourné le JSON (retour de personApi.create()) mais avant que la valeur soit assignée à p output ?
    On rappellera qu'avec le code montré, personApi.create() ne renvoie absolument pas du JSON, mais un objet PersonDto. Objet qui donc, vraisemblablement, ne contient pas les champs code ni message, ni d'ailleurs le status HTTP qui avait réellement été répondu.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  5. #5
    Membre très actif

    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    486
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 486
    Billets dans le blog
    5
    Par défaut
    Le problème, c'est qu'il y a deux écoles sur les exceptions, celle de Java de base, qui est la mienne, et décrite dans "Effective Java" (https://www.amazon.fr/Effective-Java.../dp/0134685997 ), et celle de Spring.

    Je pense que la vision Spring n'est pas bonne, mais c'est un avis perso.
    Effectivement, ça peut toujours mal se passer, soit parce que l'utilisateur envoie des données incomplètes, soit parce que la BDD tombe en panne ou que sais-je!

    Si on prend Spring, il n'y a pas d'exception dans la signature des méthodes (exemple ici: https://docs.spring.io/spring-data/c...epository.html ).

    Or, ce n'est pas vrai. En réalité, si la BDD crash, alors Spring va renvoyer une RuntimeException ( https://docs.oracle.com/javase/8/doc...Exception.html ).

    Dans "Effective Java", au contraire (et dans le Java de base), on différentie les exceptions.
    Il y a l'exception de base et la Runtime (celle envoyé par Spring) qui peut toujours être envoyé, n'importe quand.

    Il est conseillé de mettre dans la signature des méthodes les exceptions qui peuvent être envoyé suite à une erreur "prévisible" (Erreur de l'utilisateur, plantage de la BDD ...) et laisser la Runtime pour les erreurs du développeur (NullPointerException étant la plus connue).

    Dans ton cas, je crains que l'on ai pas mis en avant l'exception dans la signature de la méthode.
    Dans ce cas, on peut faire de la façon suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
     
    public void modifierPersonne() throws ServiceException{
        try{  
          //Traider input
          PersonDto output = personApi.modify(input);
          //Traiter output
        }catch(Exception e){
            throw new MyException(e);
        }
    }
    public void creerPersonne() throws ServiceException{
        try{
          //Traider input
          PersonDto output = personApi.create(input);
         //Traiter output
        }catch(Exception e){
           throw new MyException(e);
        }
    }
    Ainsi, tu te laisse le soin d'avoir une gestion centralisée des exceptions (généralement dans la couche controller).

    Tu peux aussi traiter l'éventuelle exception dirrectement (en logant ...).

    A noter que l'"Exception" est vague. Dans la réalité; le personApi jette une RuntimeException. Elle est dans une logique Spring.

  6. #6
    Modérateur

    Profil pro
    Inscrit en
    Septembre 2004
    Messages
    12 582
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Septembre 2004
    Messages : 12 582
    Par défaut
    C'est pas du tout le problème présenté -_-°.

    Que tu n'aimes pas les RuntimeException ça te regarde et ça se défend, mais on est plus que probablement dans un cas où la personne s'en tamponne si ça lui permet d'appliquer son idée.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  7. #7
    Membre émérite
    Avatar de Daïmanu
    Homme Profil pro
    Développeur touche à tout
    Inscrit en
    Janvier 2011
    Messages
    734
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Alpes Maritimes (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Développeur touche à tout

    Informations forums :
    Inscription : Janvier 2011
    Messages : 734
    Par défaut
    Citation Envoyé par thelvin Voir le message
    Bah. Peut-être et peut-être pas. Si tu as déjà utilisé des aspects tu dois avoir une idée de comment ça marche n'est-ce pas ?

    Alors comment diable quelqu'un qui n'est pas toi, pourrait-il avoir la moindre idée de si c'est possible, avec ce que tu nous montres ? Je trouve étrange qu'il y ait besoin de te dire ça, sans que ça te paraisse évident dès le départ.
    Évidemment, mais le seul usage des aspects que j'ai eu jusqu'à présent était pour faire des logs d'appels de certaine fonctions précises (avec @Before). Là je me doute que c'est possible avec des aspects, mais ça m'a l'air d'être un cas d'usage beaucoup plus sophistiqué, puisqu'il faut que j'intercepte un appel. Et c'est ça que je ne savais pas faire lorsque j'ai écrit le post.

    Citation Envoyé par thelvin Voir le message
    On rappellera qu'avec le code montré, personApi.create() ne renvoie absolument pas du JSON, mais un objet PersonDto. Objet qui donc, vraisemblablement, ne contient pas les champs code ni message, ni d'ailleurs le status HTTP qui avait réellement été répondu.
    Le champ code correspond au code HTTP, qui est donc dupliqué dans le JSON. Sinon oui on est d'accord, le JSON est automatiquement converti en DTO, c'était peut-être un abus de langage de ma part.

    Cela dit, j'ai pu avancer dans l'intervalle de temps, j'ai trouvé @Around et ProceedingJoinPoint pjp; pjp.proceed() qui ont l'air de répondre à mon besoin.

    Code java : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
      @Around("appelApi()")
      public Object detecterErreurApi(ProceedingJoinPoint pjp) throws Throwable {
        Object reponseAPi = pjp.proceed();
        /**throw possible**/
        throw new ErreurApiException();
      }

    Mais ça me pose un nouveau souci. Si mon aspect lance une exception personnalisée (ErreurApiException). ça provoque une erreur de compilation de type UndeclaredThrowableException car modifierPersonne n'a pas throws ErreurApiException déclaré.
    Je pourrais lancer une exception standard, mais si possible j'aimerais garder mon exception.
    :hola: Je fais appel aux esprits de Ritchie, Kernighan, Stroustrup et Alexandrescu :hola:
    Donnez moi la force, donnez moi le courage de coder proprement !

  8. #8
    Membre chevronné
    Homme Profil pro
    Architecte technique
    Inscrit en
    Mai 2020
    Messages
    347
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : Architecte technique

    Informations forums :
    Inscription : Mai 2020
    Messages : 347
    Par défaut
    Malheureusement, si n'est pas une runtime et n'est pas dans la signature de ça na fonctionnera pas. Il faudrait transfomer l'exception en runtime pour que ça fonctionne (comme le suggère Thelvin).

    Si pas, vous laissez tomber l'aspect et faites un wrapper autour de cette API externe...

  9. #9
    Membre Expert
    Homme Profil pro
    Inscrit en
    Septembre 2006
    Messages
    2 963
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Septembre 2006
    Messages : 2 963
    Par défaut
    Pour ce qui est de lever une exception sans avoir à la déclarer :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public final class ExceptionThrower{
        private ExceptionThrower(){}
     
        /**
         * 
         * @param ex
         */
        public static void throwException(final Throwable ex){
            ExceptionThrower.<RuntimeException>throwsUnchecked(ex);
        }
     
        /**
         * 
         * @param toThrow
         * @throws T
         */
    @SuppressWarnings("unchecked")
        private static <T extends Throwable> void throwsUnchecked(final Throwable toThrow) throws T {
            throw (T) toThrow;
        }
    }
    et donc au lieu de

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    throw new ErreurApiException();
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ExceptionThrower.throwException(new ErreurApiException());
    à vos risques et périls, cela va sans dire.

    Quant à l'idée que "la gestion des erreurs est mal conçue et l'API peut retourner un code HTTP 200 avec des données tel que ..." c'est votre façon de voir…
    d'autres pourraient considérer que les erreurs business sont une réponse valide comme une autre et doivent être interprétées par le client
    et que seules les erreurs de fonctionnement de /communication avec d
    oivent être retournées avec un code HTTP d'erreur.


Discussions similaires

  1. [struts-layout] couleur selon valeur ds collectionItem
    Par anassinou dans le forum Struts 1
    Réponses: 3
    Dernier message: 07/07/2006, 09h10
  2. Réponses: 3
    Dernier message: 13/06/2006, 16h36
  3. comment comparer les valeurs retournés par DBGrid
    Par Ice-tea dans le forum Bases de données
    Réponses: 2
    Dernier message: 08/06/2006, 14h42
  4. Ajout n lignes selon valeur...
    Par nicburger dans le forum Access
    Réponses: 1
    Dernier message: 26/10/2005, 19h49
  5. affichage selon valeur entiere ou decimale
    Par Ankya dans le forum SQL Procédural
    Réponses: 7
    Dernier message: 04/05/2005, 10h36

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