Kontakt

Tapestry and JSR-303 Bean Validation API

Posted on Montag, 4th Januar, 2010

In the last days there has been a hype around JEE 6. One of the JSRs approved by the JCP is JSR-303 Bean Validation API. In this post I’m going to give you a preview of a nice Tapestry 5.2 feature, the JSR-303 integration library. I committed the code some weeks ago and you have to wait until Tapestry 5.2 is released if you want to use this library. You can also use the snapshots if you want to give it a try right now.

Tapestry Validation Mechanism

Tapestry provides a powerful validation mechanism which is described here. Among other things this mechanism allows you to annotate your domain model classes with the annotation @Validate. The annotation value is a comma separated list of validation constraints. Each constraint identifies a validator type and optionally a constraint value.

public class User {

    @Validate("required")
    private String username;

    @Validate("required,minlength=5")
    private String password;
}

The @Validate annotation is problematic if your domain model is used in non-Tapestry applications as well as in Tapestry applications. Your non-Tapestry application becomes dependent on Tapestry annotations.

JSR-303 Bean Validation API

The JSR 303 is a specification of the Java API for JavaBean validation in Java EE and Java SE. The JSR standardizes validation constraint declaration and provides a number of built-in constraints. Like in Tapestry the constraints are defined by constraint annotations. These annotations can be applied on properties of the JavaBeans.

public class User {

    @NotNull
    private String username;

    @NotNull @Size(min=5)
    private String password;
}

Tapestry and JSR-303 Bean Validation API

As of verison 5.2 Tapestry will provide an JSR-303 integration library that allows you to annotate your domain model with JSR-303 annotations.  The library is responsible for configuring and bootstrapping the javax.validation.Validator for you. In order to use this library you have to choose an implementation of the JSR-303 specification like Hibernate Validator 4.x. Once you have included an implementation of JSR-303 into your application the service BeanValidatorSource will create an instance of  javax.validation.ValidatorFactory which is used to create Validator instances.

The configuration of BeanValidatorSource is a list of BeanValidatorConfigurer. You can contribute a BeanValidatorConfigurer to the configuration of this service in order to participate on the configuration of javax.validation.Validator. Here is an example how to do it:

public class AppModule {

   public static void contributeBeanValidatorSource(
      OrderedConfiguration<BeanValidatorConfigurer> conf) {

      BeanValidatorConfigurer configurer
               = new BeanValidatorConfigurer() {
         public void configure(
             javax.validation.Configuration<?> aConf) {
            aConf.ignoreXmlConfiguration();
         }
      };
      conf.add("MyConfigurer", configurer);
   }
}

That’s it. If you are using the BeanEditForm component to create forms for your domain model objects you don’t have to change any of your pages. Just pass the object to be edited to the object parameter, BeanEditForm will detect the JSR 303 annotations and validate the user input accordingly.

<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
   <body>
      <t:beaneditform object="user"/>
   </body>
</html>

If you create your forms manually rather than generating them with BeanEditForm you might be interested in how to make the Form component interpret the JSR 303 annotations. Let’s have a look at a simple Login page. The properties userName and password of this page are bound to fields of the form. These properties are annotated with both Tapestry’s and JSR 303 annotation. Now to make Form component analyze the JSR 303 annotations you have to pass the object to be validated into the Forms’ parameter validate. In this examaple we pass the page instance itself.

public class Login {
   @NotNull
   @Property @Persist
   private String userName;

   @NotNull
   @Validate("minlength=10")
   @Property @Persist
   private String password;

   void onSuccess() {
      // Login the user here
   }
}
<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
   <body>
      <t:form validate="this">
         <t:errors/>

         <t:textfield t:id="userName"/>

         <t:textfield t:id="password"/>

         <input type="submit" value="Login"/>
      <t:form>
   </body>
</html>

Alternatively you can process the validation manually. For this purpose just remove validate=”this” from the template and inject the Validator into you page. Let’s see how it works.

Injecting Validator

The created javax.validation.ValidatorFactory is registered in the Tapestry Registry and can be injected into you pages, components or services to create Validator instances. You can also let Tapestry create a Validator object for you which can be injected into your page, component or service. In the following example we inject a Validator instance into the Login page and validate the use input in the onValidateForm() handler method. The violations of the constraints are then recorded in the form and presented to the user.

public class LoginPage {
   @NotNull
   @Property @Persist
   private String userName;

   @NotNull
   @Validate("minlength=10")
   @Property @Persist
   private String password;

   @Inject
   private Validator validator;

   @InjectComponent
   private Form form;

   void onValidateForm() {
      Set<ConstraintViolation<LoginPage>> errors
           = validator.validate(this, Default.class);

      for (ConstraintViolation<LoginPage> next : errors) {
         form.recordError(next.getMessage());
      }
   }

   void onSuccess() {
      // Login the user here
   }
}

Limitations

Unfortunately the JSR 303 doesn’t cover the client-side validation, so that most web frameworks supporting this JSR will come up with proprietary solutions. Tapestry’s integration library doesn’t provide any client-side validators for JSR 303 annotations so far. I’ll announce this missing feature in a separate post. Stay tuned.

 

 

avatar

Your name

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

 

Tapestry 5 Blog - Copyright © 2009 - Eclectic Theme by Your Inspiration Web - Powered by WordPress