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

Langage Java Discussion :

Réflection sur Generics


Sujet :

Langage Java

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    920
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 920
    Par défaut Réflection sur Generics
    Bonjour,
    Je ne sais pas si mon approche est la bonne et est possible.
    Je vous explique ce que je souhaite faire:
    Je souhaite faire un composant Swing de type textuel dans lequel l'utilisateur peut introduire des mots (ex des tags) séparés par un séparateur (ex ";"). A chaque saisie du séparateur j'essaye d'identifier un objet d'une liste d'objets connus dont le toString() == le mot introduit. Si je ne trouve pas de correspondant, je crée un nouvel objet et je l'ajoute à la liste des objets connus.
    Voilà pour le décor.
    Même si Swing n'implémente pas les génériques, j'essaye que mon composant les implémente. Donc ma classe à la tête suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    public class TagTextField<T> extends ... {
         public TagTextField(Set<T> availabletags) { ... }
    Comme je disais plus haut si après saisie du séparateur par l'utilisateur je ne trouve pas d'objet correspondant je vais en construire un.

    Donc j'aimerais trouver un Constructor pour T prenant une String en entrée.

    Problème je n'arrive pas à mêler Reflection et Generic.

    En lisant cette FAQ sur les génériques + la javadoc sur java.lang.reflect j'avais cru comprendre qu'en écrivant
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    Field field=this.getClass().getDeclaredField("value") // où le champ value est de type T
    Type type=field.getGenericType()
    if (type instanceof Class) Constructor c=((Class)type).getDeclaredConstructor(String.class)
    mais je reçois systématiquement un NoSuchFieldException.

    Alors possible, pas possible mon idée ?

    Merci,

    Laurent

  2. #2
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    les génériques sont une aide à la compilation (évitent de se tapper des casting et des instanceof partout). Vouloir les atteindre par reflection n'a donc pas de sens. Dans ton cas, ton code va retourner "object" quand tu va demander le type de "value". Si tu avai déclaré ta classe comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TagTextField<T extends Machin>
    tu aurais eu "Machin" comme type de value.

    Pour ce que tu cherche à faire, le plus "propre" je pense est ceci:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
     
    public interface StringBasedFactory<T> {
        public T createByString(String s);
    }
    public class TagTextField<T> extends ... {
         public TagTextField(Set<T> availabletags, StringBasedFactory<T> factory) { ... }
         ....
            T newValue = factory.createByString(stringValue);
         .....
    As toi alors d'implémenter la factory en fonction du type en question.

  3. #3
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    920
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 920
    Par défaut
    Merci pour cette solution, jolie et très simple d'utilisation, à défaut de pouvoir mêler Réflection et Generic. Par contre là je ne suis pas convaincu que ce soit tellement illogique. Mais bon, passons.

  4. #4
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    Citation Envoyé par lvr Voir le message
    Par contre là je ne suis pas convaincu que ce soit tellement illogique. Mais bon, passons.
    Lorsque ta classe (TagTextField) est compilée, la valeur de T n'est pas connue. Tout son code est donc compilé avec le type de T déclaré en début de fichier via la directive <T extends ....> (dans ton cas, 'Object' puisqu'il ny a pas une telle directive). Donc quand tu interrogera par réflection sur les type déclaré de ton champ 'value' se sera un type déclaré Object.

    Quand tu écrit ceci en java (je prend l'exemple de la liste):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    List<String> l = new ArrayList<String>();
    l.add("texte");
    String value = l.get(0);
    Le compilateur traduit les appels comme ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    List l = new ArrayList();
    l.add("texte");
    String value = (String)l.get(0);
    autrement dit, c'est l'appelant et non pas l'appelé qui est le gestionnaire du type réellement utilisé dans tes générique. Donc le code de list, tout comme ton code de TagTextField n'a pas accès au type réel, il se content de déclarer que ce type est cohérent dans ses méthodes.

  5. #5
    lvr
    lvr est déconnecté
    Membre éclairé Avatar de lvr
    Profil pro
    Responsable de projet fonctionnel
    Inscrit en
    Avril 2006
    Messages
    920
    Détails du profil
    Informations personnelles :
    Localisation : Belgique

    Informations professionnelles :
    Activité : Responsable de projet fonctionnel
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Avril 2006
    Messages : 920
    Par défaut
    Ok pour un getDeclaredConstructor, mais pour un getConstructor, puisqu'au moment où je fais l'appel j'ai une classe bien concrète (String, URL, ...) ?

  6. #6
    Expert éminent
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 482
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Par défaut
    non, a aucun moment tu ne travaille dans ton code sur la valeur réelle de value. Tu travaille sur sa déclaration:
    Type getGenericType()
    Returns a Type object that represents the declared type for the field represented by this Field object.

    Sa déclaration c'est "T" avec "T extends Object". Donc getGenericType va te retourner un Objet.

    Tout au mieux, si value n'est pas null, tu aurais pu faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    value.getClass().getDeclaredConstructor(String.class)

    Comem déjà expliqué, ce n'est pas la classe générique qui gère le type runtime, c'est son appelant, il est donc impossible d'avoir le type réel depuis l'objet Class.

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

Discussions similaires

  1. Réflection sur une méthode pour la Javadoc
    Par deathness dans le forum Général Java
    Réponses: 4
    Dernier message: 25/04/2012, 15h53
  2. réflection sur champ
    Par robert_trudel dans le forum Débuter avec Java
    Réponses: 1
    Dernier message: 16/09/2009, 23h13
  3. Demande de la doc français sur Generic Heterogeneous Services
    Par riyahi dans le forum Administration
    Réponses: 2
    Dernier message: 23/07/2007, 17h51
  4. Probleme de lecture sur un generic
    Par volivi dans le forum VB.NET
    Réponses: 5
    Dernier message: 08/05/2007, 16h40
  5. lock sur generic.dictionary
    Par volivi dans le forum Général Dotnet
    Réponses: 1
    Dernier message: 08/05/2007, 16h37

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