Tuesday, February 22, 2005

Developpement avec Eclipse

Voici mon config pour faire du developpement web en Java. Sur le site d'eclipse wtp, il y a une serie de tutoriaux pour se faire la main avec WTP. Si en plus vous ĂȘtes sur Minislack, tout est nickel !

Thursday, February 10, 2005

Programmation par Contrat avec Spring

Voici une solution simple pour faire de la programmation par contrat (design by contract) avec Spring. Le contrat représente les préconditions, postconditions associés aux méthodes.

Voici ce que permet cette solution :

* possibilité de définir des préconditions, postconditions et autres tests.

* possibilité d'ajouter ou de retirer le contrat en éditant le fichier de configuration xml.

* le contrat est défini par programmation java (pas de grammaire spéciale à apprendre ou de recompilation du code pour ajouter le contrat).


Dans votre configuration xml au lieu de retourner directement la classe d'implémentation. Il faut retourner le contrat associé à l'interface. La classe d'implémentation est appelé par le contrat. Lorsque le développement du système est terminé, si vous voulez retirer les tests de préconditions et postconditions, il suffit de changer la configuration xml pour retourner directement la classe d'implémentation sans contrat.

Avec cette méthode le contrat est indépendant de la classe d'implémentation. Il est seulement associé à l'interface du service. Le contrat peut donc être appliqué sur un autre classe d'implémentation sans nouveaux codes à produire. Les assertions, qui n'ajoutent rien de fonctionnel, n'alourdiront plus le code inutilement.

<bean id="UtilisateurDao" class="org.nadeau.dao.ContratUtilisateurDao">
    <property name="implementation">
        <value>ca.nadeau.dao.UtilisateurDaoImpl</value>
    </property>
</bean>


Voici l'interface d'un service pour lequel nous produirons le contrat.

package org.nadeau.dao;

public interface UtilisateurDao {
    Utilisateur getUtilisateur(int numero);
    void setUtilisateur(Utilisateur utilisateur);
}


Voici le contrat associé à l'interface UtilisateurDao.

package org.nadeau.dao;

import org.springframework.util.Assert;

public class ContratUtilisateurDao extends ContratSupport implements UtilisateurDao{
    public Utilisateur getUtilisateur(int numero){
        //preconditions
        Assert.state(numero >= 0, "Le parametre numero de l'utilisateur doit etre plus grand que 0.");

        Utilisateur utilisateur = ((UtilisateurDao)implementation).getUtilisateur(numero);

        //postconditions
        Assert.notNull(utilisateur, "L'objet en retour ne doit pas etre null");

        return utilisateur;
    }

    public void setUtilisateur(Utilisateur utilisateur){
        //preconditions
        Assert.notNull(utilisateur, "Le parametre utilisateur ne doit pas être null");

        ((UtilisateurDao)implementation).setUtilisateur(utilisateur);
    }
}


Voici la classe utilitaire de base pour tous les contrats. Cette classe sert à instancier la classe d'implémentation.

package org.nadeau.contrat;

import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

public class ContratSupport implements Contrat, InitializingBean {
    protected Object implementation;

    public void setImplementation(String implementation){
        try {
            Class classe = Class.forName(implementation);
            this.implementation = BeanUtils.instantiateClass(classe);
        } catch(ClassNotFoundException e) {
            throw new RuntimeException(e);
        }
    }

    public void afterPropertiesSet() throws Exception {
        Assert.notNull(implementation, "Il faut donner une classe d'implementation dans l'application context");
    }
}


L'interface qu'un contrat doit respecter.

package org.nadeau.contrat;

public interface Contrat {
    void setImplementation(String implementation);
}


L'exemple présenté utilise Spring mais il est très simple d'utiliser la même approche avec un autre type de factory pour obtenir le service. Il faut simplement que la factory retourne le contrat et la classe d'implémentation au lieu de retourner seulement la classe d'implémentation.

Avant de trouver cette solution, j'ai essayé de définir mes contrats à l'aide d'intercepteurs avec Spring Aop. Ça fonctionne aussi très bien. Mais le code à produire est beaucoup plus important et la configuration xml plus importante et difficile à maintenir.

Je suis ouvert aux commentaires et suggestions.

This page is powered by Blogger. Isn't yours?