Tuesday, February 22, 2005
Developpement avec Eclipse
Voici mon config pour faire du developpement web en Java.
- Eclipse 3.1 (www.eclipse.org)
- WTP (http://eclipse.org/webtools/)
- Tomcat (http://jakarta.apache.org/tomcat/)
- Spring (http://www.springframework.org/)
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.
Voici l'interface d'un service pour lequel nous produirons le contrat.
Voici le contrat associé à l'interface UtilisateurDao.
Voici la classe utilitaire de base pour tous les contrats. Cette classe sert à instancier la classe d'implémentation.
L'interface qu'un contrat doit respecter.
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.
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.