Cycle de vie Facelets et la JSTL

J’ai souvent lu dans des forums et des blogs que la JSTL ne s’intègre pas du tout avec Facelets et qu’il faut absolument éviter d’utiliser les deux technologies ensemble. C’est faux à condition de bien connaître Facelets :
Cycle de vie d’une requêtes Facelets
Rappelons d’abord le cycle de vie d’une requête JSF. Lorsque l’utilisateur demande une page JSF, sa requête provoque coté serveur l’exécution suivante :
- Restore view
- Apply request values
- Process validation
- Update model value
- Invoque application
- Render request
Avec Facelets, il y a un cycle de vie en deux phases :
- Compile : création d’un “component tree” dans une “UIViewRoot”
- Run (exécution du cycle de vie JSF)
On peut remarquer que Facelets fonctionne de la même façon que les JSP (compilation de la JSP puis exécution de cette dernière). Pourquoi ces deux phases existent-elles ? Facelets est composé des TagHandlers (compile-time) et des ComponentHandlers (invocation JSF). Voici la liste triée de ces composants :
- TagsHandlers
- c:forEach
- c:choose
- c:set
- c:if
- f:facet
- f:actionListener
- f:valueChangeListener
- ui:include
- ui:decorate
- ui:composition
- Tous les autres Tags tierces
- ComponentHandlers
- ui:repeat
- ui:fragment
- ui:component
- f:view
- f:verbatim
- f:selectItems
- h:inputText
- h:datatable
- Tous les autres composants tierces
Pour information, voici deux bons article sur le sujet pour aller plus loin dans les détails : http://www.ilikespam.com/blog/c:foreach-vs-ui:repeat-in-facelets et http://www.znetdevelopment.com/blogs/tag/facelets/.
Tag de la JSTL
Facelets n’implémente que certaines fonctions de la JSTL :
- <c:if/>
- <c:forEach/>
- <c:catch/>
- <c:set/> (utilisation déconseillée)
Les autres tag de la JSTL ne fonctionnent pas car ils ne sont pas implémentés. C’est l’occasion de remarquer qu’en utilisant les tags JSTL dans une application Facelets, on ne se base pas sur la version standard des composants mais sur une version re-développée par Facelets.
Il faut donc se méfier car certains tag ne fonctionnent pas exactement de le même façon. Par exemple, l’attribut varStatus du tag <c:forEach/> pointe sur l’instance d’un objet de type com.sun.facelets.tag.jstl.core.IterationStatus et non de type javax.servlet.jsp.jstl.core.LoopTagStatus comme décrit dans la documentation de la JSTL. Certaines méthodes ne sont pas implémentées. Dans ce cas il est donc préférable de se fier qu’a la documentation de référence de Facelets et non celle de la JSTL. Pour la javadoc, je ne l’ai trouvé qu’en téléchargements Facelets ici.
Pour information, visiblement, dans JSF2.0, Facelets utilise désormais la version standardisée de la JSTL.
Workaround sur l’utilisation de <c:set/>
Lorsque l’on commence à utiliser la JSTL on est vite tenté d’utiliser des variables dans les boucles <c:forEach/> d’où l’utilisation du tag déconseillé <c:set/>. Il est cependant possible de contourner le problème en utilisant une autre fonctionnalité de Facelets. En effet, il est possible d’utiliser le tag <ui:include/> avec des paramètres pour contourner l’utilisation de la fonctionnalité déconseillée de la JSTL. Sans compter que cela permet de découper les pages XHTML en petits fragments ce qui peut rentre le code plus facile à lire et à maintenir.