JAXenter.de

Das Portal für Java, Architektur, Cloud & Agile
X

Alle Infos zur aktuellen JavaOne gibt's in unserer Serie: JavaOne 2014.

FacesTales

„Drum prüfe, wer sich ewig bindet!“

Lars Röwekamp und Matthias Weßendorf

Die Überprüfung von Nutzereingaben, z. B. innerhalb eines Formulars, gehört zu den Standardaufgaben eines Webframeworks. JSF 2.0 bietet gleich mehrere Ansätze, um diese Aufgabe zu bewerkstelligen. Doch welcher Ansatz ist der richtige? Und viel wichtiger: sind die JSF-2.0-Bordmittel für reale Projekt ausreichend?

Standardvalidierung

Die meisten JSF-Einführungen und Tutorials sehen vor, dass die Validierung von Nutzereingaben innerhalb der View deklarativ hinterlegt wird. Dieser Ansatz, bei dem das JSF-Eingabefeld ein zusätzliches <f:validate... /> Child Tag spendiert bekommt, hat den Charme, dass Eingabefeld und zugehörige Validierungsregel unmittelbar miteinander verknüpft und somit für jedermann ersichtlich sind. Klassische Vertreter dieser Validatorenzunft sind <f:validateLenght .../ >, <f:validateLongeRange .../ >, <f:validateDoubleRange .../ >. Neu hinzugekommen sind in JSF 2.0 die beiden Validatoren <f:validateRequired .../ > und <f:validateRegex .../ >. Die Liste der zur Verfügung stehenden Validatoren macht schnell ersichtlich, dass es sich hierbei nur um die Spitze des Eisbergs handeln kann.

Reichen die JSF-2.0-Standardvalidatoren nicht aus, können eigene Validatoren geschrieben und mittels Method-Expression an das validator-Attribut einer JSF-Eingabekomponente gebunden werden. Eine Möglichkeit zur Umsetzung eines eigenen JSF-Validators ist die Implementierung einer JSF ManagedBean, welche wiederum eine Methode beliebigen Namens mit folgender Signatur enthält:

public void validate(FacesContext ctx, UIComponent component, Object value) 
  throws ValidatorException;

Alternativ zu dem eben beschriebenen Ansatz kann eine Validatorklasse auch das javax.faces.Validator- bzw. das javax.faces.FormatValidator-Interface implementieren und via faces-config.xml-Eintrag oder @FacesValidator Annotation (seit JSF 2.0) innerhalb der Anwendung bekannt gemacht werden. In beiden Fällen, wird der Validator dann durch ein spezielles Child-Tag <f:validator validatorId="..." /> an das zu prüfende JSF-Eingabeelement gebunden, wobei validatorId den eindeutigen Namen des neuen Validators angibt.

Benötigt man innerhalb des eigenen Validators zusätzlich Attribute, die als Parameter übergeben werden sollen, dann muss zwingend ein eigenes Validator Tag her, das von ValidatorTag oder FormatValidatorTag ableitet und zusätzlich die gewünschten Attribute unterstützt. Achtung: parametrisierte Validatoren sind "stateful" Validatoren, d. h. sie verlieren ihren State - also auch die Werte der übergebenen Parameter - wenn diese nicht explizit via StateHolder-Interface-Methoden saveState(...)und restoreState(...) gesichert.

So weit, so gut - oder auch nicht. So einfach der JSF-Standardmechanismus zur Validierung auch sein mag, so groß sind auch seine Probleme im Zusammenhang mit umfangreichen "Real-Life"-Projekten. Zum einen ist die Validierung an die View und nicht an das Modell gebunden, was automatisch dazu führt, dass weitere Mechanismen zur Validierung für die anderen Schichten benötigt werden. Zum anderen ist die Validierung innerhalb der View mit jeweils einer Komponente verbunden. Eine komponentenübergreifende - a.k.a. Cross-Component - Validierung ist dabei nicht vorgesehen.

Bean Validation

Eine Lösung für das erste Problem - die strikte View-Bindung - bietet JSF seit der Version 2.0 durch die Integration des in JSR 303 beschriebenen Bean-Validation-Ansatzes [1]. Dank JSR 303 ist es innerhalb einer JSF-basierten Webanwendung möglich, eine metadatenbasierte, schichtenübergreifende Validierung an dem Domain-Modell aufzuhängen. Listing 1 zeigt ein einfaches Beispiel.

Listing 1: Bean Validation in Aktion
public class Person {

   @NotNull
   private String firstName; 

   @NotNull
   private String name; 

   @NotNull @Min(value = 0) @Max(value = 15)
   private Integer children;     
   ...
}

Neben den in Listing 1 gezeigten Constraints bietet das Bean Validation API zusätzlich noch folgende an:

  • @AssertTrue, @AssertFalse
  • @DecimalMax, @DecimalMin, @Size, @Digits
  • @Past, @Future
  • @Pattern
  • @NotNull

Voraussetzung für die Verwendung von Bean Validation ist natürlich, dass eine entsprechende Implementierung in der Laufzeitumgebung zur Verfügung steht. Dies ist generell gegeben, wenn man sich im JavaEE-6-Umfeld bewegt. Alternativ lassen sich auch zusätzliche Libraries einbinden. Mögliche Kandidaten sind hier die Referenzimplementierung Hibernate Validator [2], das Apache-Incubator-Projekt Bean Validation (ehemals agimatec Validation, [3]) oder aber das Apache-MyFaces-Projekt External Validation (a.k.a. extVal, [4]).

Ein weiterer Vorteil, der sich durch die Verwendung von Bean Validation ergibt, ist die Möglichkeit zur Gruppierung von Validierungsregeln, die bei Bedarf aktiviert oder deaktiviert werden können. Listing 2 zeigt eine leicht modifizierte Version des ersten Beispiels unter Verwendung des Gruppenfeatures. In dem Beispiel gehen wir davon aus, dass es neben "realen" Personen auch "juristische" Personen gibt, die nicht unbedingt über einen Vornamen und eine Anzahl von Kindern verfügen.

Listing 2: Bean Validation mit Gruppierung
public class Person {
   
   private boolean human; 

   @NotNull(groups = HumanPerson.class)
   private String firstName; 

   @NotNull
   private String name; 

   @NotNull(groups = HumanPerson.class) ...
   private Integer children;     
   ...
}
 
Verwandte Themen: 

Kommentare

Ihr Kommentar zum Thema

Als Gast kommentieren:

Gastkommentare werden nach redaktioneller Prüfung freigegeben (bitte Policy beachten).