Einsatz von c:-Tags in JSF-Seiten

Die schon etwas ältere JavaServer Pages Standard Tag Library (JSTL) bringt einige nützliche Tags für die Kontrolle des Aufbaus von XHTML-Seiten mit sich. Die Core-Bibliothek enthält iterative und konditionale Tags, die sowohl von JSP als auch von JSF interpretiert werden können. Sie werden in der Regel unter dem c-Namensraum eingebunden, z.B. c:if,c:forEach.

Wenn JSF eine XHTML-Seite einliest, um auf einen Request zu reagieren, baut es mit Hilfe der auf der Seite enthaltenen Tags einen Komponentenbaum auf. Die in den JSF-Tags angegebenen Ausdrücke (z.B. rendered) werden dabei noch nicht ausgewertet. Die JSTL-Tags hingegen werden von JSF wie ein Präprozessor bereits beim Aufbau des Komponentenbaums interpretiert und können ihn dadurch beeinflussen. Bei ihrem Einsatz gibt es deswegen einige Dinge zu beachten, damit es in der laufenden Anwendung nicht zu unerwartetem Verhalten oder sogar Exceptions kommt.

Konditionale Tags (c:if, c:choose, c:when)

Für JSF-Tags ist es egal, ob sie oder ihr Container später gerendert werden, ihre entsprechenden Komponenten finden sich intern im Baum wieder. Das gilt aber nur noch bedingt, wenn konditionale JSTL-Tags ins Spiel kommen.

Wenn eine c:if-Bedingung als negativ ausgewertet wird, werden die Tags innerhalb des c:if-Tags nicht mehr eingelesen/ausgewertet und sind deswegen nicht im Komponentenbaum enthalten. Es handelt sich also um eine schöne Möglichkeit, den Komponentenbaum unter bestimmten Umständen schlank zu halten und performant zu sein.

Was man aber unbedingt beachten muss: Das Ergebnis der Bedingung darf sich zur Lebenszeit der Seite, also über mehrere Requests auf der Seite, nicht ändern. Dadurch würde der Komponentenbaum im nächsten Request ggf. plötzlich Elemente enthalten, die vorher nicht da waren, bzw. andere Elemente würden entfallen. Leider speichert JSF den Komponenten-State in einem komplizierten Geflecht aus Arrays, wofür es wichtig ist, dass die Komponenten im Baum beim State-Restore an derselben Stelle stehen wie beim State-Save. Ansonsten kommt es beim Wiederherstellen des Komponenten-State zu Fehlern, bevorzugt zur IndexOutOfBoundsException.

Ein „guter“ (erlaubter) c:if-Ausdruck wäre beispielsweise die Abfrage einer Berechtigung, da sich diese in der Regel nicht ändert. Bei fehlender Berechtigung wird hier die Verwaltung von Komponenten gespart.

Ein „schlechter“ (fehleranfälliger) c:if-Ausdruck wäre die Abfrage eines Werts, der sich aus einer Benutzereingabe auf derselben Seite ergibt, da dieser den Komponentenbaum zur Lebenszeit der Seite verändert. Für diesen Fall sollte man bei einzelnen Komponenten die rendered-Eigenschaft verwenden bzw. bei ganzen Bereichen das ui:fragment oder andere Container.

Iterative Tags (c:forEach)

Für das Schleifen-Tag c:forEach gilt derselbe Grundsatz wie bei den konditionalen Tags. Durch seine Anwendung werden im Baum je nach Schleifenausdruck unterschiedlich viele Komponenten erzeugt. Der Ausdruck sollte sich daher nur auf zur Laufzeit unveränderliche Listen beziehen. Für veränderliche Listen sollte das ui:repeat-Tag verwendet werden.

Verwendung von EL-Variablen in c:-Tags

Variablen aus JSF-Tags wie die Zeilenvariable einer Tabelle oder die Schleifenvariable eines ui:repeat können in einem JSTL-Ausdruck nicht angesprochen werden, da sie zum Zeitpunkt der Auswertung des c:-Tags noch gar nicht existieren. Umgekehrt können JSTL-Variablen durchaus in EL-Ausdrücken verwendet werden.

Verfasst von Marion Wilker am 10. Januar 2017