Wicket JSR-303 Validators

Data validation is a necessary and critical task, yet often a burden since the validation rules have to be duplicated in almost all layers (persistent layer, client-side, server-side). Reflection around this unavoidable issue, resulted into the inception of the JSR-303 Bean Validation, leaded by Emmanuel Bernard, which provides a standardized way of implementing such validation across various application domain. Our project aims at integrating this JSR into Wicket.
The project is hosted at GoogleCode. We provide numerous unit tests covering most use cases, however, if you cannot find your specific need, don’t hesitate to participate and send us some feedback via the bugtracker.

What is the JSR 303 Bean Validation ?

The specififation addresses the validation issue by providing a standardized API, as well as a meta-data model of validation constraints which can be applied as annotations on a JavaBean object. Thus, those rules can be used within all your application’s layers, resulting in a much less cluttered and redundant code.

What does the Wicket JSR-303 Validators library provide ?

This library provides validation against data received via a form submission, it is based on the JSR 303 API for that purpose. It’s compatible with Java >= 1.5 and Wicket >= 1.4.
Two validators are available :

  • BeanPropertyValidator implements IValidator. It must be added to a form input with a text type. It provides validation for a single annotated field.
  • JSR303FormValidator implements IFormValidator. It must be added to a Form to validate all of its children FormComponents.

Warning : those validators only support Forms with a CompoundPropertyModel, we’ll see why in the following example usage.
The library supports :

  • Validation on all or a single form components
  • Annotations
  • Annotations inheritance form super classes and interfaces
  • Validation of object graph with the @Valid annotation
  • Group validation and @GroupSequence annotation

In progress :

  • Annotations on methods
  • Custom error messages with a custom message interpolator
  • Class level validation
  • Other models than AbstractPropertyModel and CompoundPropertyModel
  • More FormComponent types, other than AbstractTextComponent

Sample usage

Let’s see how to use the library in a concrete project. There are several requierements for our project to work correctly. First, we obviously need the Wicket JSR303 Validators library, you can download it from the GoogleCode page and install it in your maven repository with this command :

 $ mvn install:install-file -Dfile=/path/to/wicket-jsr303-validators-1.0-SNAPSHOT.jar                                   -DgroupId=com.zenika.wicket.contrib                                   -DartifactId=wicket-jsr303-validators                                   -Dversion=1.0-SNAPSHOT -Dpackaging=jar

Now we can add the dependencies to our pom :

  • The Wicket JSR303 Validators library
  • An implementation of the JSR303 API, we chose the reference implementation Hibernate Validator 4.0
<dependency>     <groupId>com.zenika.wicket.contrib</groupId>     <artifactId>wicket-jsr303-validators</artifactId>     <version>1.0-SNAPSHOT</version> </dependency>
<dependency>     <groupId>org.hibernate</groupId>     <artifactId>hibernate-validator</artifactId>     <version>4.0.2.GA</version> </dependency>

The JSR303 API is only available from the JBoss maven repository so we need to add it to our pom as well :

<repository>     <id>repository.jboss.org</id>     <name>JBoss Maven Repository</name>     <url>http://repository.jboss.com/maven2/</url> </repository>

The validation process will be executed with the JSR303 constraints placed on our JavaBean. Here is a sample business object we could use :

public class Person implements Serializable {       private static final long serialVersionUID = 1L;       @Min(value = 18)     private int age;       @Size(min = 2, max = 255)     private String firstName;       @NotNull     @Size(min = 2, max = 255)     private String lastName;       public int getAge() {         return age;     }       public String getFirstName() {         return firstName;     }       public String getLastName() {         return lastName;     }       public void setAge(int age) {         this.age = age;     }       public void setFirstName(String firstName) {         this.firstName = firstName;     }       public void setLastName(String lastName) {         this.lastName = lastName;     }       @Override     public String toString() {         return "Person [age=" + age + ", firstName=" + firstName + ", lastName=" + lastName + "]";     }   }

The annotations are quite self-explanatory.
We can now add the proper validator in Wicket :

public class HomePage extends WebPage {       private static final long serialVersionUID = 1L;       private static final Logger LOG = LoggerFactory.getLogger(HomePage.class);       /**      * Constructor that is invoked when page is invoked without a session.      *      * @param parameters      *            Page parameters      */     public HomePage(final PageParameters parameters) {       Person person = new Person();       final Form<Person> personForm = new Form<Person>("personForm", new CompoundPropertyModel<Person>(person));       personForm.add(new TextField<String>("firstName"));     personForm.add(new TextField<String>("lastName"));     personForm.add(new TextField<Integer>("age"));       personForm.add(new Button("submit") {          private static final long serialVersionUID = 1L;          @Override         public void onSubmit() {             LOG.info("Submitted " + personForm.getDefaultModelObjectAsString());             personForm.info("Submitted " + personForm.getDefaultModelObjectAsString());        }     });       personForm.add(new JSR303FormValidator());       add(personForm);     add(new FeedbackPanel("feedback"));       } }

Our page provides a form to add an object of type Person. The only required step to add validation is to supply the form with a JSR303FormValidator.
Be careful to use a CompoundPropertyModel with the form, as the JSR-303 will access your bean fields via Reflection.
Don’t forget to add a FeedbackPanel so that your user can see the validation error reports.
Here is the associated markup :

<html xmlns:wicket="http://wicket.apache.org/dtds.data/wicket-xhtml1.4-strict.dtd" >     <head>         <title>Wicket JSR303 Validators</title>     </head>     <body>         <strong>Person Form</strong>         <br/><br/>         <form wicket:id="personForm">             <label>First Name : </label> <input type="text" wicket:id="firstName" /><br />             <label>Last Name : </label> <input type="text" wicket:id="lastName" /><br />             <label>Age : </label> <input type="text" wicket:id="age" /><br />             <input type="submit" wicket:id="submit" />         </form>         <div wicket:id="feedback"></div>     <
/body> </html>

The final step is to test :

 $ mvn jetty:run

Conclusion

As we stated earlier, don’t be afraid to send us some feedback at http://code.google.com/p/wicket-jsr303-validators/issues/list.

2 pensées sur “Wicket JSR-303 Validators

  • 1 mars 2010 à 10 h 54 min
    Permalink

    Bonjour,

    Merci beaucoup pour ce retour et votre effort autour de Wicket. Je crois qu’il manque encore deux éléments pour rendre la solution utilisable dans la vraie vie :
    + l’annotation des messages d’alerte/erreur
    + l’annotation sur les méthodes métier pour permettre de traiter les cas limites en fonction des règles de gestion concernées.
    Hélàs, je suis trop full pour pouvoir contribuer au projet. J’appelle donc le monde entier pour aider Zenika à aller plus loin dans la démarche initiée.

    Répondre

Laisser un commentaire

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.

%d blogueurs aiment cette page :