03.10.2012
Bean-Validation mit JEE6 - JSR-303
In diesem Artikel wird beschrieben was unter Bean-Validation zu verstehen ist und wie es einsetzt wird, um Werte zu validieren. D.h. es wird überprüft, ob übergebenen Funktionsparameter bestimmten Regeln entsprechen.
In dem folgenden Beispiel wird eine JSF-Seite mit einem Eingabefeld und einem Button erstellt. In das Eingabefeld kann eine ISBN-Nummer eingetragen und durch ein Klick auf den Button in eine Datenbank geschrieben werden. Bevor der Wert abgelegt wird, soll er allerdings validiert werden, damit keine inkonsistenten Daten in der Datenbank landen.
Das Eingabefeld der JSF-Seite ist mit einem Presentation-Model (Backing-Bean) verbunden, das den Zugriff auf eine Entity ermöglicht. Der Button löst beim Klick einen Funktionsaufruf zum Speichern des Werts aus. Auch dieser läuft über das Presentation-Model (Backing-Bean).
Die Validierung passiert in der Entity und wird mittels Annotationen vorgenommen.
Falls die Architektur dieser kleinen "Anwendung" unklar sein sollte, dann kann man in dem JEE6-Tutorial weitere Informationen und Erklärungen zu dem Thema finden.
Als erstes legen wir eine Entity an, die eine id
und eine ISBN
-Nummer besitzt. Wichtig sind die Annotationen @NotNull
und @Size
. Einerseits wird damit festgelegt, dass die ISBN-Nummer nicht leer sein darf und die Länge mindestens 18 Zeichen, aber maximal 30 Zeichen lang sein darf. Außerdem wird eine Fehlermeldung definiert, die angezeigt wird, wenn der Eingabewert ungültig ist. Es ist anzumerken, dass die Überprüfung auf @NotNull
redundant ist und in einer realen Anwendung weggelassen werden kann.
package org.hameister.isbn; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; /** * * @author Hameister */ @Entity public class ISBN implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @NotNull @Size(min = 18, max = 30, message="ISBN-Nummer hat die falsche Länge! Der die Länge muss zwischen 18 und 30 Zeichen liegen.") private String isbn; public String getIsbn() { return isbn; } public void setIsbn(String isbn) { this.isbn = isbn; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } }
Falls man die Entity nicht mit einem Wizard, wie beispielsweise bei NetBeans möglich, anlegt, dann darf man die Datei persistence.xml
nicht vergessen.
<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"> <persistence-unit name="ISBNValidationDemoPU" transaction-type="JTA"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <jta-data-source>jdbc/sample</jta-data-source> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/> </properties> </persistence-unit> </persistence>
Außerdem wird noch eine Stateless Session Bean benötigt. Diese besitzt eine Methode addISBN
, die die Entity über den Entity-Manager in die Datenbank schreibt.
package org.hameister.isbn; import javax.ejb.Stateless; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; /** * * @author Hameister */ @Stateless public class ISBNStore { @PersistenceContext EntityManager em; public void addISBN(ISBN entity) { em.persist(entity); System.out.println("Added:"+ entity.getIsbn()); } }
Hinweis: Ggf. muss noch eine Datei beans.xml
mit folgendem Inhalt angelegt werden:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd"> </beans>
Das Presentation-Model sieht folgendermaßen aus:
package org.hameister.isbn; import javax.ejb.EJB; import javax.enterprise.context.RequestScoped; import javax.inject.Named; /** * * @author Hameister */ @Named @RequestScoped public class IsbnPM { private ISBN isbn = new ISBN(); @EJB ISBNStore bean; public ISBN getEntity() { return isbn; } public void setEntity(ISBN entity) { this.isbn = entity; } public void store() { bean.addISBN(isbn); } }
Es wird mittels der Annotation @EJB
die Session Bean injeziert, so dass in der Methode store
die ISBN-Nummer gespeichert werden kann. Außerdem wird für das erstellte Objekt vom Typ ISBN
ein getter und ein setter benötigt.
Die JSF-Seite enthält ein Eingabefeld inputText
und einen Button commandButton
, die, wie weiter oben beschrieben, verbunden sind.
<?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xmlns:h="http://java.sun.com/jsf/html"> <h:head> <title>ISBN-Validation</title> </h:head> <h:body> <h:form> ISBN: <h:inputText value="#{isbnPM.entity.isbn}"/> <h:commandButton value="Add" action="#{isbnPM.store()}" /> </h:form> </h:body> </html>
Nachdem wir das Beispiel in ein war-Archiv gepackt und auf einem Application-Server deployt haben, wird folgendes im Browser zu sehen sein, wenn eine invalide ISBN-Nummer eingetragen wird:

In dem Beispiel wurde eine sehr einfach Regel überprüft. Es ist allerdings auch möglich komplexere Regeln mittels regulärer Ausdrücke zu überprüfen. Dafür kann die Annotation @Pattern
verwendet werden. Den folgenden regulären Ausdruck habe ich auf der Seite GeekZilla gefunden.
package org.hameister.isbn; import java.io.Serializable; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.validation.constraints.NotNull; import javax.validation.constraints.Pattern; import javax.validation.constraints.Size; /** * * @author Hameister */ @Entity public class ISBN implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id; @Pattern(regexp = "ISBN\\x20(?=.{13}$)\\d{1,5}([- ])\\d{1,7}\\1\\d{1,6}\\1(\\d|X)$", message="Die ISBN-Nummer hat das falsche Format. Ein eine gültige Eingabe sieht bespielsweise folgendermaßen aus: ISBN 1-56389-668-0") private String isbn; public String getIsbn() { return isbn; } public void setIsbn(String isbn) { this.isbn = isbn; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } }
Neben den drei angesprochenen Annotation zum Validieren existieren noch weitere Möglichkeiten die Gültigkeit eines Wertes zu überprüfen. Beispielsweise: AssertFalse
, @AssertTrue
, @DecimalMax
, @DecimalMin
, @Digits
, @Future
, @Max
, @Min
, @NotNull
, @Null
, @Past
, @Pattern
, @Size
Genauere Erklärungen dazu findet man in folgendem Dokument von Oracle: Using Bean Validation
Weitere Informationen
Die Bean Validation 1.0 ist in JSR-303 beschrieben. Hier findet man das PDF mit der Spezifikation dazu.
- JEE6-Tutorial
- EJB-Tutorial
- TimerService
- Interceptors
- REST-Schnittstelle
- Remote Zugriff auf EJBs mit einem Standalone-Java-Client
- Unit-Tests für EJBs mit einem Embeddable-Container