TP7

NFP121 - TP7

NFP 121 - TP7

Introspection




Tp7Enoncé

Question 1

Mon code de la "calculette", en déclenchant par introspection une des méthodes de la classe java.lang.Math

Seules les méthodes retournant un "double", attendant un ou deux paramètres de type double sont sélectionnables.


TableMethodesJavaLangMath :


package question1;

import java.lang.reflect.Method;
import java.util.TreeMap;
import java.util.Map;
import java.util.NoSuchElementException;

/** Gestion par introspection des méthodes de la classe java.lang.Math,<br>
 *  Seules sont conservées :les méthodes retournant un double et d'arité 1 ou 2<p>
 *   Note : Emploi du Pattern Singleton pour cette table, accessible uniquement en lecture par des accesseurs<p>
 * La convention de nommage est la suivante :
 *        le "Nom" de la fonction suivi de "(double)"  exemple : "sqrt(double)"
 *  ou le "Nom" de la fonction suivi de "(double, double)"  exemple : "IEEEremainder(double, double)"
 */

final public class TableMethodesJavaLangMath{
    /** Singleton */
    private static TableMethodesJavaLangMath instanceUnique = null;

    public static TableMethodesJavaLangMath getInstance(){
        synchronized(TableMethodesJavaLangMath.class){
            if (instanceUnique==null){
                instanceUnique = new TableMethodesJavaLangMath();
            }
            return instanceUnique;
        }
    }

    private TableMethodesJavaLangMath(){
    } 
    // fin du Singleton

    /** 
     * @param  nomDeLaMéthode Nom de la fonction + "(double)" ou "(double, double)"
     * @return true si la fonction est présente
     */
    public boolean cetteMethodeEstPresente(String nomDeLaMethode){
        return tableDesMethodes.containsKey(nomDeLaMethode);
    }

    /** 
     * @param  nomDeLaMéthode Nom de la fonction + "(double)" ou "(double, double)"
     * @return true si la fonction est binaire, d'arité 2
     * @throws NoSuchElementException si la méthode demandée n'existe pas
     */
    public boolean cetteMethodeAttendDeuxParametres(String nomDeLaMethode)throws NoSuchElementException{
        if(!cetteMethodeEstPresente(nomDeLaMethode)){
            throw new NoSuchElementException();
        }

        if(nomDeLaMethode.contains("(double, double)")){
            return true;
        }else{
            return false;
        }
    }

    /** 
     * @param  nomDeLaMéthode Nom de la fonction + "(double)" ou "(double, double)"
     * @return true si la fonction est unaire, d'arité 1
     * @throws NoSuchElementException si la méthode demandée n'existe pas 
     */
    public boolean cetteMethodeAttendUnSeulParametre(String nomDeLaMethode)throws NoSuchElementException{
        if(!cetteMethodeEstPresente(nomDeLaMethode)){
            throw new NoSuchElementException();
        }

        if(nomDeLaMethode.contains("(double)")){
            return true;
        }else{
            return false;
        }

    }

    /** 
     * Obtention de la liste ordonnée des méthodes
     * @return la liste triée des fonctions issues de java.lang.Math
     */  
    public String[] listeDesMethodes(){
        String [] tab = new String[tableDesMethodes.size()];

        int compteur = 0;
        for(String s: tableDesMethodes.keySet()){
            tab[compteur] = s;
            compteur++;
        }
        return tab;
    }

    /** Invocation d'une méthode de la table
     * @param  nomDeLaMéthode Nom de la fonction + "(double)"
     * @param arg1 l'opérande
     * @return un résultat
     * @throws NoSuchElementException si la méthode demandée n'existe pas ou une exception levée par la fonction appelée
     */
    public double invoquer(String nomDeLaMethode,double arg1) throws Exception{
        try{
            if(this.cetteMethodeAttendUnSeulParametre(nomDeLaMethode)){

                Class cl = Class.forName("java.lang.Math");

                Object result = tableDesMethodes.get(nomDeLaMethode).invoke(cl, new Object[]{arg1});
                return (Double)result;
            }else{
                throw new NoSuchElementException();
            }
        } catch (NoSuchElementException e){
            throw new NoSuchElementException();
        }
    }

    /** Invocation d'une méthode de la table
     * @param  nomDeLaMéthode Nom de la fonction + "(double, double)"
     * @param arg1 l'opérande
     * @return un résultat
     * @throws NoSuchElementException si la méthode demandée n'existe pas ou une exception levée par la fonction appelée
     */  
    public double invoquer(String nomDeLaMethode, double arg1, double arg2) throws Exception{
        try{
            if(this.cetteMethodeAttendDeuxParametres(nomDeLaMethode)){
                Class cl = Class.forName("java.lang.Math");

                Object result = tableDesMethodes.get(nomDeLaMethode).invoke(cl , new Object[]{arg1, arg2});
                return (Double) result;
            }else{
                throw new NoSuchElementException();
            }
        } catch (NoSuchElementException e){

            throw new NoSuchElementException();

        }
    }

    /**
     * Le dictionnaire contient la liste des méthodes disponibles.
     * un choix de dictionnaire pourrait être pour la Clé 
	          une String soit le Nom de la fonction + "(double)" ou "(double, double)".<br>
     *  et en Valeur =  la Method correspondante.
     *  ou tout autre choix
     */
    private static Map<String,Method> tableDesMethodes = null;

    /** bloc statique d'intialisation de la table des méthodes */
    static{
        tableDesMethodes = new TreeMap<String,Method>();
        try{
            Class cl= Class.forName("java.lang.Math");
            for(Method m: cl.getMethods()){
                boolean isDouble = true;
                boolean endParam = false;
                int compteur = 0;
                while(endParam == false && isDouble == true){
                    for(Class param: m.getParameterTypes()){
                        if(param.getName()!= "double"){
                            isDouble = false;
                        } else {
                            compteur++;
                        }

                        if( m.getReturnType().getName()!= "double"){
                            isDouble = false;
                        }
                    }
                    endParam = true ;
                }
                if (isDouble){
                    if(compteur == 1){
                        tableDesMethodes.put(m.getName()+"(double)", m);
                    }else if (compteur == 2){
                        tableDesMethodes.put(m.getName()+"(double, double)", m);
                    }
                }
            }
        }catch(Exception e){
        }

    }

}



Question 2

Cette question est une application du cours


lierObservableEtObserver :


public static void lierObservableEtObserver(Object observable, Object observer) throws NoSuchElementException{

        try{
            String obs = observable.getClass().getName();
            Class cl = Class.forName(obs);
            Class[] types = new Class[] { Observer.class };
            Method m = cl.getMethod("addObserver", types );
            m.invoke(observable , new Object[]{observer});
        }catch(Exception e){
            throw new NoSuchElementException();
        }

    }

delierObservableEtObserver :


public static void delierObservableEtObserver(Object observable, Object observer) throws NoSuchElementException{

        try{
            String obs = observable.getClass().getName(); //"java.util.Observable"
            Class cl = Class.forName(obs);
            Class[] types = new Class[] { Observer.class };
            Method m = cl.getMethod("deleteObserver", types);
            m.invoke(observable , new Object[]{observer});
        }catch(Exception e){
            throw new NoSuchElementException();
        }
    }

lierSourceEtListener :


public static void lierSourceEtListener(Object source, Object listener) throws NoSuchElementException{
        try{
            Class clListener = listener.getClass();
            Class clSource = source.getClass();
            boolean invoked = false;

            for(Method m: clSource.getMethods()){
                if(m.getParameterCount()==1){
                    if(m.getName().contains("add") && m.getParameterTypes()[0].isInstance(listener)){
                        m.invoke(source , listener);
                        invoked = true;
                    }

                }
            }
            if(!invoked){
                throw new NoSuchElementException();
            }

        }catch(Exception e){
            throw new NoSuchElementException();
        }

    }

delierSourceEtListener :


 public static void delierSourceEtListener(Object source, Object listener) throws Exception{
        try{
            Class clListener = listener.getClass();
            Class clSource = source.getClass();
            boolean invoked = false;

            for(Method m: clSource.getMethods()){
                if(m.getParameterCount()==1){
                    if(m.getName().contains("remove") && m.getParameterTypes()[0].isInstance(listener)){
                        m.invoke(source , listener);
                        invoked = true;
                    }
                }

            }
            if(!invoked){
                throw new NoSuchElementException();
            }

        }catch(Exception e){
            throw new NoSuchElementException();
        }
    }



Question 3

Question très difficile, malgré mes différents test et l'aide du forum,je ne suis parvenu à avoir tous les tests jnews bons ... il m'en reste 8 qui ne passent pas.

Par contre avec l'aide de Pellier les tests jnews sont ok. Merci à toi


Introspection :


public class Introspection{
    public static Set<Method> getHeritees(String nomDeLaClasse) throws ClassNotFoundException{
        
        Class c = Class.forName(nomDeLaClasse);
        // méthodes définies dans la class à tester
        Set<Method> methodesDefiniesLocalement = new HashSet<Method>(Arrays.asList(c.getDeclaredMethods()));
        // méthodes définies dans les class parentes de la class à tester
        // (public ou protected) et non abstraite
        Set<Method> methodesHeritees = new HashSet<Method>(Arrays.asList(c.getDeclaredMethods()));
        // méthodes héritées non redéfinies (ce que nous cherchons)
        Set<Method> methodesHeriteesNonRedefinies = new HashSet<Method>();

        // récupère les méthodes des class parentes
        Class parent = c;
        Set<Method> methodesAAjouter;
        int mod;

        while(parent.getSuperclass() != null){
            parent = parent.getSuperclass();
            methodesAAjouter = new HashSet<Method>(Arrays.asList(parent.getDeclaredMethods()));
            for(Method m : methodesAAjouter){
                // la class n'est pas déjà définie dans une des superClass inférieures
                if( !Introspection.ContientMethode(methodesHeritees, m)){
                    mod = m.getModifiers();
                    // class public ou protected et non abstraite
                    if(     mod != 0
                        &&  (Modifier.isPublic(mod) || Modifier.isProtected(mod))
                        &&  !Modifier.isAbstract(mod)
                      ){
                        methodesHeritees.add(m);
                    }
                }
            }
        }

        // soustraction
        // methodesHeritees - methodesDefiniesLocalement
        for(Method m1 : methodesHeritees){
            if(!Introspection.ContientMethode(methodesDefiniesLocalement,m1) ){
                methodesHeriteesNonRedefinies.add(m1);
            }
        }

        return methodesHeriteesNonRedefinies;

    }

    public static void main(String[] args) throws ClassNotFoundException{
        for(Method m : Introspection.getHeritees("java.util.AbstractCollection")){
            System.out.println(m);
        }
    }
    private static boolean MethodesEgales(Method m1, Method m2){

        Class[] param1 = m1.getParameterTypes();
        Class[] param2 = m2.getParameterTypes();

        // égalité de nom
        if(!m1.getName().equals(m2.getName())) return false;

        // égalité des paramètres
        if(param1.length != param2.length) return false;
        for(int i = 0 ; i < param1.length ; i++){
            if(! param1[i].getName().equals(param2[i].getName()) ) return false;
        }
        // égalité des types de retours
        if(!m1.getReturnType().equals(m2.getReturnType())) return false;

        return true;

    }
    private static boolean ContientMethode(Set<Method> set, Method m){
        boolean present = false;
        for(Method m2 : set){
            if(Introspection.MethodesEgales(m,m2)) {
                return true;
            }
        }
        return false;
    }

}

Plusieurs tests ont été effectués mais malgré cela je n'ai pas trouvé la solution ...




Conclusion, biliographie et remarques :

Tp très intéressant, il m'a demandé pas mal d'investissement surtout la question3 ...

Ajouter un commentaire