Bonjour,

Je dois, par introspection, être capable de retrouver dans un bean une propriété qui renvoie une liste d'entiers, c'est à dire une propriété accessible en lecture et renvoyant un objet de type List<Integer>.

Ce n'est pas si trivial que cela et j'ai mis un petit moment à mettre le code au point. Ca fonctionne correctement (visiblement), ceci dit, je trouve ça un peu lourd; quelqu'un aurait-il une solution plus élégante ?

En gros le principe est de chercher une propriété ayant une méthode de lecture (getter) dont le type retour est une sous classe de List et est un type paramétré. On regarde ensuite les paramètres en question et on ne retient que les méthodes dont le type retour ne contient qu'un seul paramètre de type Integer.

Voici le code :

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
 
/**
 * Paquet de définition
 */
package tests.reflect;
 
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
 
 
/**
* Classe permettant de tester la recherche d'une propriété paramétrée 
* dans un bean.
* 
* L'objectif est de savoir si l'on est capable de trouver dans un bean une propriété 
* dont le type est List<Integer>.
*/
 
public class FindParameterizedPropertyTest {
 
  /**
  * Un exemple de bean qui contient une propriété 
  * simple et une propriété paramétrée de type liste. 
  */
  public static class SampleBean {
 
    /**
     * Propriété simple. 
     */
    public String getName() {
      return "this is the value of name property";
    }
 
    /**
     * Propriété paramétrée de type liste.
     */
    public ArrayList<Integer> getIntegerList() {
      return new ArrayList<Integer>();
      //return (ArrayList<Integer>)Arrays.asList(Integer.valueOf(1),Integer.valueOf(2),Integer.valueOf(3));
    }
  } // fin SampleBean
 
 
  /**
   * Méthode permettant de recherche au sein d'un bean 
   * une propriété de type List<Integer> et renvoyant 
   * la valeur de cette propriété.
   * 
   * @param bean Le bean dans lequel on cherche.
   * @return La valeur de la propriété de type List<Integer> si celle 
   * ci existe ou <code>null</code> sinon. 
   * @throws Exception En cas d'erreur grâve lors de l'accès au bean.
   */
  @SuppressWarnings("unchecked")
  protected static List<Integer> getIntegerListFromBean(Object bean) 
    throws Exception {
    //
    List<Integer> listeTrouvee = null;
 
    // on cherche la liste des descripteurs de propriétés du bean.
    PropertyDescriptor[] descriptors = null;
    try {
      BeanInfo beanInfo = null;
      beanInfo = Introspector.getBeanInfo(bean.getClass());
      descriptors = beanInfo.getPropertyDescriptors();
    } catch (IntrospectionException e) {
       Exception ex = new Exception();
       ex.initCause(e);
       throw ex;
    }
 
    // On parcourt la liste des descripteurs de propriétés du bean
    for (PropertyDescriptor currentDescriptor : descriptors) {
      // 
      Method readMethod = currentDescriptor.getReadMethod();
 
      // Existe-t-il une méthode de lecture pour la propriété coutante ?
      // Et si oui, cette méthode renvoie-t-elle une sous classe de List ?
      if (readMethod != null && List.class.isAssignableFrom(readMethod.getReturnType())) {
        // Est-ce que le type retour de la méthode de lecture est un type paramétré ?
        if (readMethod.getGenericReturnType() instanceof ParameterizedType) {
          // Si oui, on cherche quel est le type paramétré en question.
          ParameterizedType parameterizedReturnType = (ParameterizedType)readMethod.getGenericReturnType();
          Type[] actualTypeArguments = parameterizedReturnType.getActualTypeArguments();
          // S'il n'y a qu'un seul argument au type paramétré et si celui-ci correspond au type Integer.
          if (actualTypeArguments.length == 1 && actualTypeArguments[0].equals(Integer.class)) {
            try {
              Object listeObject = readMethod.invoke(bean, new Object[]{});
              listeTrouvee = (List<Integer>)listeObject;
              System.out.println(currentDescriptor.getName());
              break;                                          
            } catch (IllegalArgumentException e) {
              // La méthode que l'on vient d'invoquer n'a pas la bonne signature
              // en ce qui concerne les arguments. On l'ignore.
            } catch (IllegalAccessException e) {
              // On ne gère pas le contrôle d'accès java.
            } catch (InvocationTargetException e) {
              Exception ex = new Exception("Can not read property ["+currentDescriptor.getName()+"] in that bean.");
              ex.initCause(e);
              throw e;
            }
          }
        }
      }
    }
    //
    return listeTrouvee;
  }
 
  /**
   * Méthode main.
   * 
   * @param args Les arguments passés au programme principal. 
   */
  public static void main(String[] args) {
 
    try {
      List<Integer> uneListeInteger = getIntegerListFromBean(new SampleBean());
    } catch (Exception e) {
      e.printStackTrace();
    }
 
  }
}