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 :

Classe et package "conditionnels"


Sujet :

Java

  1. #1
    Membre éclairé
    Inscrit en
    Janvier 2005
    Messages
    491
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 491
    Par défaut Classe et package "conditionnels"
    Hello,

    Dans un projet JAVA que j'ai récupéré et que je vais continuer de développer sous netbeans, il y a une erreur que j'aimerai faire disparaitre. Je m'explique:

    Suivant la présence ou non d'un certain package P, on instancie une classe A si celui ci est présent, B si non.

    Le problème se situe dans le fait que dans le code définissant la classe A, on utilise les packages, classes et méthodes existantes dans le package P. Or lorsque celui-ci est absent, une erreur est (assez logiquement je trouve) renvoyée par netbeans m'informant qu'il ne trouve pas tel package, telle classe, telle méthode etc...

    Bref, manifestement, ca n'a pas du poser problème a l'ancien développeur pour faire marcher le soft... mais j'aimerai bien éviter d'avoir ce genre de chose, et ma question est la suivante:

    y'a t-il un moyen d'éviter ce genre d'erreur? Je pense par exemple a un équivalent du #define en C, ou tout autre méthode existante...

    Je viens de me remettre au JAVA, j'en ai beauocup fait avant mais je ne me souviens pas d'une telle possibilitée...

    Merci d'avance!

  2. #2
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Il faut faire une instance dynamique. Par contre, pour une meilleure souplesse d'utilisation, il faut une interface commune entre A et B.
    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
    22
    23
    Class<MonInterfaceCommune> clazz = null;
     
    try
    {
      clazz = (MonInterfaceCommune)Class.forName( "package.complet.A" );
    }
    catch( ClassNotFoundException exc )
    {
      try
      {
        clazz = (MonInterfaceCommune)Class.forName( "package.complet.B" );
      }
      catch( ClassNotFoundException exc )
      {
        ... traitement de l'erreur car ni A ni B ne sont dispo ...
      }
    }
     
    if( clazz != null )
    {
      MonInterfaceCommune instance = clazz.newInstance();
      instance.uneMethode();
    }
    Il reste encore à catcher les autres exceptions, mais le principe est là.
    Si tu ne veux pas utiliser une interface commune, il faut appeler les méthodes dynamiquement via "getMethod" sur ton instance.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  3. #3
    Membre éclairé
    Inscrit en
    Janvier 2005
    Messages
    491
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 491
    Par défaut
    Hum oui je vois le genre... A la base mes deux classes A et B héritent d'une classe mère, mais par contre elles ont des méthodes différentes.

    En tout cas le problème subsiste si par exemple je déclare une variable d'instance provenant du package de la classe A non? Si par exemple la classe A appartient au package P.p1 et qu'elle contient une variable d'instance appartenant a P.p2...

    Merci de ton aide en tout cas...


    Edit: En effet c'est plutôt ca mon problème je me suis mal exprimé: mes classe A et B ont été crée par le développeur et sont bien instanciées comme je l'ai indiqué, sous condition. Simplement pour A, il existe des variables qui appartiennent au package qui n'est pas suceptible d'être présent, et donc lorsque ce n'est pas le cas, les noms de classes ainsi que les méthodes associés a ces variables ne sont pas reconnues...

  4. #4
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Citation Envoyé par vinzzzz Voir le message
    Edit: En effet c'est plutôt ca mon problème je me suis mal exprimé: mes classe A et B ont été crée par le développeur et sont bien instanciées comme je l'ai indiqué, sous condition. Simplement pour A, il existe des variables qui appartiennent au package qui n'est pas suceptible d'être présent, et donc lorsque ce n'est pas le cas, les noms de classes ainsi que les méthodes associés a ces variables ne sont pas reconnues...
    Il faut supprimer toutes les références en dures aux classes A et B. Si A et B dérivent d'une même classe, alors tu peux caster l'instance dynamique par cette classe mère, et utiliser les méthodes ce la classe mère.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  5. #5
    Membre éclairé
    Inscrit en
    Janvier 2005
    Messages
    491
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 491
    Par défaut
    Hum je crois que je ne me suis aps bien fait comprendre. Exemplifions ma classe A:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    Class A extends Top 
    {
        private p.p1.c1 var ;   // Ici, si P est inconnu, il y a une erreur
        ...
     
        public A ()
        {
            ...
            var = new p.p1.c1() ;  // Erreur, connait pas la classe...
            var.method(15) ;       // Idem, comme il ne sait pas ce qu'est var, il ne connait pas methode
        }
    }

    Voilà concrètement à quoi ressemble mon problème: j'aimerai garder ce principe, en supprimant les erreurs.

    J'ai regardé du coté de la classe Class. Est-ce que ce genre de chose pourrait régler le problème:

    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
     
    Class A extends Top 
    {
        private Object var ;   // On le met en tant qu'objet
        ...
     
        public A ()
        {
            ...
            // On l'instancie de manière indirecte
            var = Class.forName("p.p1.c1").newInstance() ; 
     
            // On appele les méthodes de c1 de cette manière
            var.getClass().getMethod("method", Integer.class).invoke(var, 15) ;
        }
    }
    Comme ceci ca me semblerai bon, mais le fait qu'on assigne a var le type Object me chifonne... Qu'en pense-tu?

  6. #6
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    J'en pense que c'est laid.

    Faire des method.invoke à tout bout de champ, c'est bon pour certains frameworks utilisant des fonctions avancées, mais je doute sincèrement que ce soit vraiment ton besoin.

    Tu dois repenser ta manière de procéder et utiliser une méthode semblable à celle que Dinogoban propose.

  7. #7
    Membre éclairé
    Inscrit en
    Janvier 2005
    Messages
    491
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 491
    Par défaut
    C'est sur c'est un peu lourd comme manière de faire... Je vais voire ce que je peux faire, mais comme ca je n'ai pas d'autres idées: si le package n'est pas présent, il ne reconnaitra pas les classes, donc faut trouver un moyen de les utiliser implicitement...

  8. #8
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Citation Envoyé par vinzzzz Voir le message
    C'est sur c'est un peu lourd comme manière de faire... Je vais voire ce que je peux faire, mais comme ca je n'ai pas d'autres idées: si le package n'est pas présent, il ne reconnaitra pas les classes, donc faut trouver un moyen de les utiliser implicitement...
    Euh.... oui, mais j'ai la désagréable impression que tu n'as absolument rien compris à ma solution, qui pourtant, comme le dit dingoth, résout ton problème
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  9. #9
    Membre éclairé
    Inscrit en
    Janvier 2005
    Messages
    491
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 491
    Par défaut
    Si tu le dit... En effet je n'ai pas du comprendre en quoi ta solution résoud mon problème. Je vais donc potasser ca

    EDIT: non décidément je ne vois pas... la solution que tu me propose, si j'ai bien compris, ca permet de résoudre le problème dans le cas où A n'est carrément pas disponible. Or comme je l'ai précisé, A est disponible et développée dans le projet, c'est juste qu'elle fait appel a des packages/classes qui sont suceptibles de ne pas être présents lorsqu'on compilera tout le bazard (je m'était mal exprimé dans mon post initial), occasionnant, non pas une erreur a l'execution puisque l'absence du package P sera détécté de la même manière que ce que tu m'a présenté, mais juste dans netbeans qui me refusera la construction du projet en me souligant les erreurs et en mettant en évidences l'absence des packages utilisés par A ...

    Mais peut être que quelque chsoe m'a échappé dans ta solution par rapport a mon pb...

  10. #10
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    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
    package mon.package.qui.existe;
     
    public interface MonInterface {
      // Déclaration des méthodes
    }
     
    public classe MaClasseQuiExiste implements MonInterface {
      // Implémentation des méthodes
    }
    ------------------
    package mon.package.qui.existe.pas;
     
    import mon.package.qui.existe.MonInterface;
     
    public class MaClasseQuiExistePeutEtre implements MonInterface {
      // Implémentation des méthodes
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    MonInterface monObjet = null;
    try {
      monObjet = (MonInterface) (Class.forName("mon.package.qui.existe.pas.MaClasseQuiExistePeutEtre").newInstance(params));
    } catch (ClassNotFoundException e) {
      monObjet = new MaClasseQuiExiste(params);
    }
     
    // Faire plein de trucs avec monObjet.
    Je ne vois pas en quoi ceci est compliqué... pourtant cela fait exactement ce que tu souhaites. Que le package mon.package.qui.existe.pas soit présent ou non, Java compilera. Cependant, c'est vrai qu'il faut pouvoir modifier le code de MaClasseQuiExistePeutEtre pour lui faire implémenter MonInterface.

  11. #11
    Membre éclairé
    Inscrit en
    Janvier 2005
    Messages
    491
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 491
    Par défaut
    Ceci n'est en effet pas compliqué mais ca n'est pas adapté à mon problème:

    Si je reprend ton exemple, MaClasseQuiExistePeutEtre (classe A par rapport a ce que j'ai dit avant) existe dans mon projet. Simplement elle n'est instanciée que lorsque le package P est détécté car elle contient des variables de classes qui proviennent de celui-ci. A ce niveau aucun problème...

    Si P existe, j'instancie A, sinon j'instancie B. A et B sont deux classe que l'on a crée et qui utilisent deux librairies différentes pour faire une même tâche. B a été implémenté par les développeurs du projet, mais A fait appel a un package externe P.
    Si P n'existe pas, en théorie j'instancie B, aucun problème niveau execution, mais le projet ne compile pas car les classes utilisées par A ne sont pas reconnues puisque P n'existe pas...

    De plus je n'ai pas accés en modification au package P: c'est un package payant et non open-source...

  12. #12
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    Non, je n'assume pas du tout le fait que le package existe ou non. Enfin, à l'exécution. Car au développement, tu en as besoin de ce package, hein !

    Effectivement, le problème semble de plus en plus clair.

    Deux choses :

    1. La logique de ma méthode est toujours bonne, mais l'implémentation doit être adaptée.

    2. Un pattern Factory peut t'aider :
    a) Tu crées une classe qui utilise ton package P comme s'il était effectivement présent. Elle seule doit utiliser ce package. Elle implémentera une interface I.
    b) Tu crées ensuite une classe qui étend I et a le comportement dans le cas où le package P n'est pas disponible.
    c) Tu crées ensuite une méthode factory qui fera ceci : dans le cas où P existe (en utilisant Class.forName() et en attrapant l'exception), tu instancies la première classe et dans le cas contraire, tu instancies l'autre. Dans les deux cas, tu renvoies l'instance. Et tu utilises les méthodes de ton interface sur cette instance.

    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
    22
    23
    24
    25
    26
    public interface MonInterface {
      public void maMethode();
    }
     
    public class MaClasseUtilisantLAutrePackage implements MonInterface {
      public void maMethode() {
        com.company.package.utile.ObjetCool objet = //...
      }
    }
     
    public class MaClasseUtilisantNotrePackage implements MonInterface {
      public void maMethode() {
        // ...
      }
    }
     
    public class MonInstanceFactory {
      public MonInterface creerInterface () {
        try {
          Class.forName("com.company.package.utile");
          return new MaClasseUtilisantLAutrePackage();
        } catch (ClassNotFoundException e) {
          return new MaClasseUtilisantNotrePackage();
        }
      }
    }
    La beauté de la chose, c'est que Java se foutra complètement de la seconde classe (et donc des imports qui risquent d'être foireux) si tu ne l'instancies pas, ou ne l'utilises pas.

    La laideur de la chose, c'est que nous utilisons les exceptions pour faire un if, mais je ne vois pas comment faire proprement.

  13. #13
    Modérateur
    Avatar de dinobogan
    Homme Profil pro
    ingénieur
    Inscrit en
    Juin 2007
    Messages
    4 073
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2007
    Messages : 4 073
    Par défaut
    Citation Envoyé par vinzzzz Voir le message
    Si P existe, j'instancie A, sinon j'instancie B. A et B sont deux classe que l'on a crée et qui utilisent deux librairies différentes pour faire une même tâche. B a été implémenté par les développeurs du projet, mais A fait appel a un package externe P.
    Si P n'existe pas, en théorie j'instancie B, aucun problème niveau execution, mais le projet ne compile pas car les classes utilisées par A ne sont pas reconnues puisque P n'existe pas...

    De plus je n'ai pas accés en modification au package P: c'est un package payant et non open-source...
    On s'est mal compris sur les noms des classes A et B, il fallait simplement adapter
    Donc je reprend :
    1. Dans A, tu dois instancier les classes du package P de manière dynamique, pas le choix.
    2. Il te faut une interface commune entre A et B pour utiliser les instances de manière transparente.
    3. tu dois faire un pré-traitement avant de foncer tête baisser dans l'instanciation de A pour savoir si le package P est disponible. Je vois bien une méthode static dans A du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    public static A getInstance()
    {
      ... si package P disponible, return new instance A
      ... sinon return null
    }
    Si le "getInstance" renvoi null, alors tu instancies B.

    Ca répond à ton problème ?

    EDIT : grillé par dingoth
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java
    Que la force de la puissance soit avec le courage de ta sagesse.

  14. #14
    Membre éclairé
    Inscrit en
    Janvier 2005
    Messages
    491
    Détails du profil
    Informations forums :
    Inscription : Janvier 2005
    Messages : 491
    Par défaut
    Citation Envoyé par dingoth Voir le message
    Non, je n'assume pas du tout le fait que le package existe ou non. Enfin, à l'exécution. Car au développement, tu en as besoin de ce package, hein !
    Non pas forcément (je sens que ca va vous faire hurler, vous développeurs chevronés)... En fait je l'utilise trés peu, en tout je fais appel a deux méthodes appartenant à deux classes pécifiques de ce package... Je peux donc théoriquement développer sans l'avoir installé (ce qui est le cas en ce moment), juste en connaissant l'API, mais justement ca ne passe pas niveau compilation (ce qui est normal)...

    Je pense que c'est ca qui vous échappe: le package P étant payant, pour le moment mon labo n'a pas pu acheter de licence pour qu'on puisse ne serai-ce que recompiler le soft. Autrement dit, lorsque j'ouvre mon projet, le package est absent, et la compilation ne peut avoir lieu vu que celui-ci est utilisé en dur dans le code (dans la classe A)...

    Donc je cherche une solution (temporaire je pense) pour pallier à ca et compiler tranquilement le code sans me soucier de l'absence de ce package, qui, présent ou non, ne pose aucun pb a l'execution. Car dans l'absolu, je pense comprendre tout a fait vos propositions, et je pense qu'elles sont même déjà implémentées dans le code: Si je précise la structure du code, ca ressemble plus ou moins à ce que vous proposez:

    Je dispose d'une classe abstraite, disons M, qui hérite de JInternalFrame, et qui contient:
    - Une méthode abstraite, setMolecule()
    - Une méthode statique permettant de tester la présence ou non du package P. C'est cette méthode que j'appele pour savoir si je vais instancier A ou B lors de l'execution (à l'aide de Class.forName).

    Mes classes A et B définies précédements héritent de cette classe abstraite, et implémentent chacune la méthode setMolecule. Simplement, A utilise le package externe P suceptible d'être absent (car horriblement cher), et utilse en particulier une variable d'instance ayant un type défini dans le package P et héritant de javax.swing.JRootPane.

    En tout cas merci pour le temps que vous m'avez consacré . J'ai carrément mal formulé ma requete je m'en rend compte maintenant...

  15. #15
    Membre Expert
    Profil pro
    Inscrit en
    Mai 2004
    Messages
    1 252
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 252
    Par défaut
    Oulalala ! tu veux compiler une classe sans avoir le package qu'elle utilise ?

    Bah, tu connais les méthodes à utiliser ? Dans ce cas, rien de plus simple : tu crées les classes que tu vas utiliser avec les méthodes que tu vas utiliser.

    Par exemple, tu vas utiliser la classe com.company.LeurClasse, et de cette classe, tu vas utiliser les méthodes "public void méthode1() throws MonException" et "public String méthode2(int aaa, String bbb)".

    Dans ce cas, tu crées le code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    package com.company;
     
    public class LeurClasse implements LeurInterface, java.io.Serializable {
      public void méthode1 () throws MonException () {
        // rien du tout!
      }
     
      public String méthode2 (int aaa, String bbb) {
        return "";
      }
    }
    Tu l'utilises pour développer et compiler, mais avant de builder ton propre jar, tu enlèves cette classe.

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