:: Enseignements :: Master :: M1 :: 2013-2014 :: Java Avancé ::
[LOGO]

Map et réflection


Implantation de l'interface Map en utilisant la reflection.

Exercice 1 - Map et introspection

Le but de cet exercice est d'écrire une méthode asMap qui prend un objet en paramètre et le voit comme une Map<String, Object>.
Par exemple, avec la classe Point ci-dessous:

le code suivant doit afficher {x=2, y=3, class=class fr.umlv.reflect.Point}.
       Point p = new Point(2, 3);
       Map<String, Object> map = Introspectors.asMap(p);
       System.out.println(p);
     
La méthode asMap marche de la façon suivante: pour chaque méthode getFoo() présente dans la classe de l'objet passé en paramètre, elle associe, dans la table de hachage, (a) une clé foo qui correspond au nom de la méthode sans le "get" et avec la première lettre en minuscule, et (b) une valeur qui est la valeur renvoyée par l'appel à la méthode. La valeur correspondant à une clé n'est pas calculée une fois pour toutes lors de la création de la Map mais à chaque fois que l'on accède à la valeur. En ça, la Map agit comme une vue de l'objet.
Par exemple, le code suivant doit afficher {x=3, y=4, class=class fr.umlv.reflect.Point}.
       Point p = new Point(2, 3);
       Map<String, Object> map = Introspectors.asMap(p);
       p.translate(1, 1);
       System.out.println(p);
     
Mais, avant d'implanter asMap, nous allons implanter un certain nombre de méthodes de support. Nous aurons besoin d'une interface de support Getter et nous travaillerons dans la classe Introspectors.


  1. Rappeler à quoi sert l'annotation @FonctionalInterface sur l'interface Getter.
  2. On cherche à écrire dans la classe Introspectors une méthode getGetterMap qui prend en paramètre une classe et renvoie une Map qui associe à une String, l'objet Getter correspondant.
    Quelle doit être la signature de la méthode getGetterMap ?
    Sachant que l'on va utiliser les méthodes property et invokeGet, compléter la méthode invokeGet pour appeler la méthode getter qui correspond à un getter sur l'objet object passé en second paramètre.
    Attention à la gestion des exceptions.
    Implanter la méthode getGetterMap, sachant vous avez parfaitement le droit d'utiliser l'API des streams pour cela.
  3. Rappeler à quoi sert la classe java.lang.ClassValue.
    Comment pouvons nous l'utiliser ici ?
  4. Sachant que l'on veut déclarer l'instance de ClassValue comme une constante (static final), quelle doit être la déclaration du champ GETTER_MAP_VALUE pour que la ClassValue.get renvoie une Map qui associe des String à des Getter correspondant à la classe passée en paramètre.
  5. Essayer d'initialiser le champ GETTER_MAP_VALUE et expliquer pourquoi cela ne compile pas.
    Comment modifier la déclaration de GETTER_MAP_VALUE pour que cela compile.
  6. Expliquer pourquoi, même si cela compile, ce n'est pas ce que l'on veut ?
    Quel est le problème avec la façon dont l'interface Getter est déclarée ?
  7. Créer une interface SimpleGetter n'ayant pas le problème de Getter.
    Ecrire la méthode getSimpleGetterMap qui marche de la même façon que getGetterMap mais renvoie une Map dont les valeurs sont des SimpleGetter.
  8. Changer la déclaration de GETTER_MAP_VALUE pour utiliser l'interface SimpleGetter.
  9. Rappeler à quoi sert la classe abstraite AbstractMap.
    Ecrire la méthode asMap sachant que la Map renvoyée doit être non modifiable et vérifier que l'implantation marche avec les tests unitaires IntrospectorsTest.java.
  10. Expliquer pourquoi il est intéressant de redéfinir la méthode get de la Map renvoyée par la méthode asMap.
    Ecrire le code correspondant.