Neues aus der Java-Welt: JavaServer Faces 2.3

Seite 3: Neuigkeiten II

Inhaltsverzeichnis

JSF konvertiert sowie validiert alle Eingaben und überträgt sie nach erfolgreicher Prüfung in das Datenmodell. Sind jedoch zwei Felder voneinander abhängig, stößt das Verfahren der Einzelvalidierung an seine Grenzen. Beispielsweise könnte die Eingabe in einem Feld abhängig vom Inhalt eines anderen Feldes variieren. Hier ist eine Multi-Feld-Validierung erforderlich. Bisher mussten das Programmierer selbst erledigen. Da zum Zeitpunkt der Validierung die Daten noch nicht in das Datenmodell übertragen wurden, war der Zugriff auf die Rohdaten im Komponentenbaum erforderlich. Das wird in Zukunft mit dem Tag <f:validateWholeBean> deutlich einfacher.

Die JSF-Expertengruppe hat sich darauf verständigt, hier keine auf JSF zugeschnittene Validierung zu spezifizieren, sondern auf die Möglichkeiten der Bean Validation zurückzugreifen. Hierbei wird das Datenmodell mit entsprechenden Annotationen versehen. Da Bean Validation beim Datenmodell greift, JSF die Daten aber erst bei erfolgreicher Validierung in das Modell überträgt, war intern eine Änderung des Vorgehens erforderlich: Die Daten werden in eine temporäre Kopie des Modells übertragen und validiert. Erst wenn das erfolgreich ist, kommt es zur endgültigen Übernahme der Daten. Für Webentwickler, die JSF nutzen, erfolgt der Vorgang jedoch völlig transparent im Hintergrund.

Auch diese Funktion ist im aktuellen Stand via Eintrag in der web.xml einzuschalten:

<context-param>
<param-name>javax.faces.validator.ENABLE_VALIDATE_WHOLE_BEAN</param-name>
<param-value>true</param-value>
</context-param>

JSF macht sich den Umstand zunutze, dass sich in Bean Validation Gruppen definieren lassen. Damit können Entwickler das Verhalten mehrerer Attribute zueinander prüfen. Bei der Seitendefinition können sie für jede UI-Komponente eine oder mehrere dieser Gruppen angeben, zum Beispiel die Default-Gruppe – die ohne Angabe einer Gruppe immer implizit genutzt wird – sowie eine weitere für die gemeinsame Prüfung. Soll beispielsweise das Alter wahlweise für das erste Lebensjahr in Tagen, ansonsten aber in Jahren angegeben werden, können Entwickler in einer JSF-Seite zwei Eingabefelder integrieren.

<h:inputText id="ageDays" value="#{grouper.ageDays}">
<f:validateBean id="ageValidator" validationGroups=
"javax.validation.groups.Default,de.muellerbruehl.jsf23.Age"/>
</h:inputText>
<h:message for="ageDays"/>

<h:inputText id="ageYears" value="#{grouper.ageYears}">
<f:validateBean validationGroups=
"javax.validation.groups.Default,de.muellerbruehl.jsf23.Age"/>
</h:inputText>
<h:message for="ageYears"/>

<f:validateWholeBean value="#{grouper}"
validationGroups="de.muellerbruehl.jsf23.Age" id="ageValidator"/>

Diesen Feldern werden mittels <f:validateBean> zwei Validierungsgruppen zugewiesen. Im Beipiel ist eine davon die Default-Gruppe. Sie wird automatisch jedem Constraint zugewiesen, für das nicht explizit eine andere Gruppe angegeben wurde. Im vorliegenden Fall sind das die Wertebereiche von @Min bis @Max der Klasse Grouper.

@Named
@RequestScoped
@ValidGrouperAge(groups = de.muellerbruehl.jsf23.Age.class)
public class Grouper implements ConstraintValidator<ValidGrouperAge,
Grouper> {

@Override
public void initialize(ValidGrouperAge constraintAnnotation) { }

@Override
public boolean isValid(Grouper grouper, ConstraintValidatorContext
context) {
return grouper.getAgeDays() == 0 && grouper.getAgeYears() > 0 ||
grouper.getAgeDays() > 0 && grouper.getAgeYears() == 0;
}

@NotNull @Min(0) @Max(365)
private int ageDays;

@NotNull @Min(0) @Max(124)
private int ageYears;

[getter / setter]
}

Die Validierung der Einzelwerte erfolgt somit gemäß den annotierten Bedingungen (z. B. @Min). Beide Felder zusammen werden in der ....Age-Gruppe validiert. JSF erkennt das am Tag <f:validateWholeBean>, das in der Seitendefinition nach den Einzelfeldern anzugeben ist. Diese Prüfung findet man in der überschriebenen isValid-Methode. Details zur Validierung von Gruppen lassen sich in der Spezifikation der Bean Validation nachlesen.

JSF 2.3 wird die WebSocket-Technik unterstützen. Wie sie genau ausgestaltet wird, ist derzeit noch in der Diskussion. Da noch nicht jeder Browser mit WebSockets umgehen kann, war lange Zeit eine Fallback-Möglichkeit auf eine andere Verbindungstechnik, vorzugsweise SSE (Server-Side Events), vorgesehen. Entsprechend nennt die Vorabspezifikation das Tag <f:socket>.

SSE selbst ist jedoch (noch) nicht standardisiert. Und so wurde nach Veröffentlichung des EDR in der Expertengruppe das Thema weiter diskutiert und an der WebSocket-Kommunikation weitergefeilt. Dabei wurde wegen der fehlenden Standardisierung auf SSE verzichtet. So soll das Tag voraussichtlich <f:websocket> heißen und klar zeigen, welche Technik es unterstützt. Weil das noch im Fluss ist, sei hier auf passende Code-Beispiele verzichtet.

JSF basiert auf Servlets. Hier wird mit Servlet 4.0 an der kommenden Spezifikation gearbeitet, die auf HTTP/2 aufsetzt und mit Java EE 8 erscheinen soll. Das bereits spezifizierte HTTP/2 kann mit einer Verbindung mehrere Anfragen übertragen. Das wirkt sich positiv auf die Performanz aus. Die Spezifikation von Servlet 4.0 geschieht unter dem JSR 369. Wenn auch noch nicht abgeschlossen, ist zu erwarten, mdas JSF von der ihr profitieren wird. Servlet 4.0 definiert unter anderem einen Server-Push. Möglicherweise nutzt das eine spätere Version von JSF und ergänzt so die WebSockets.