JSF 2.0 ClientBehavior: Bean Validation in JavaScript
Door: Jan-Kees van Andel, 17 March 2010In the following article I’m going to show you my first “real world” ClientBehavior and my first impressions from a user’s perspective.
First, some theory. JSF has support for something called “attached objects”. This has been since the very beginning, with Converters and Validators.
Since JSF 2.0, Behaviors have been added to this list. A Behavior, when attached to a component, adds client side scripts to an object. For example, one can imagine a Behavior to do an Ajax request, load some data and show it on the page. This will be a common use case for behaviors. The Expert Group understood this and came up with a specialized AjaxBehavior, which is quite similar to the Ajax4jsf <:a4jsupport /> tag. it adds Ajax functionality to the existing component, without modifying it.
This is ClientBehavior in a nutshell. There are more subtile things to know, see this article by Andy Schwartz for a more thorough explanation of the subject.
From now on, I assume at least basic ClientBehavior knowledge and of course JSF knowledge.
The ValidateBean Behavior
With Java EE 6 we got Bean Validation. And I must admit, I like it a lot. It has a nice declarative language and one ubiquitous model for defining validations for your entire system, from database (generating Bean Validation-aware DDL with JPA 2.0) to UI (the JSF 2.0 BeanValidator, which I implemented for Apache MyFaces. That’s where my enthusiasm started).
But, one validation is missing in the spec (with good reasons of course), namely client side JavaScript validations, to improve usability and decrease server load.
Especially since JavaScript validations are often skipped because of maintenance reasons (validations implemented twice) and we now have a robust platform to implement generic validations, I tried to combine the two new technologies (ClientBehavior and Bean Validation) into one generic JavaScript validator.
The ClientBehavior implementation
This class has some interesting things. First, of course the annotations. @FacesBehavior simply registers the class as a ClientBehavior under the given name, just like how Managed Beans or Converters work. The second annotation defines a @ResourceDependency. A ResourceDependency simply says: “Hey JSF, I generate markup which depends on this file. Make sure it’s available”. And JSF 2.0 responds with: “Okay, I will”.
Also, you probably noticed my ClientBehavior to only understand buttons. That’s right, you need to attach it to a button and it takes care of wiring all field validations in the form.
It also looks for a messages component. This is used later to make sure the JS error messages are positioned the same as the by JSF generated messages. UIMessages applies to the entire view, so I don’t just look in the form. A high performance implementation may choose to start searching near the form, since most messages are positioned there, but that’s way out of scope of this article.
I know, I know, this is not the most elegant piece of code, but it nicely illustrates the point. I simply aggregates as much validation metadata as possible and writes it into one big JavaScript statement. Not that optimal, but high performance implementations may choose to dynamically generate a JS file with all metadata which only needs to be referenced from the inline JS code.
If you’d like to know how to obtain the ConstraintDescriptors (the four method calls in the above snippet), just look for the BeanValidator in the Apache MyFaces SVN. I reused the same code here.
The JavaScript
The JavaScript shown below is part of the static scripts that belong to the ValidateBeanBehavior. It contains the JavaScript code to execute the rules, as passed from the server and, if needed, show the validation errors.
It’s a lot of code, which, in essence, validates all input fields in the given form, according to the given validation rules and shows the user an error if needed. This error is positioned at the same spot as where the UIMessages would have been rendered in case of a server side error. This is a best guess though, because when the messages are not rendered (i.e. on the initial request), there is no marker in the page that I can use for positioning. A more sophisticated implementation could enrich all UIMessages in the page to always write some marker “div” with an ID to the client.
I’m going to skip the rest of the JavaScript. It’s just a bunch of validations and utilities, like utilities to convert Strings to and from Date Objects, based on a SimpleDateFormat pattern. This pattern is part of the generated JavaScript and is obtained by looking at the attached Converters.
Usage in a Facelet
To make the ClientBehavior a bit easier to use, here’s a Facelets taglib which defines a tag for the ClientBehavior (don’t forget to configure the taglib in web.xml or put it in the /META-INF of a JAR).
With the taglib in place, we can use the ClientBehavior, like this:
That’s not too much effort for a client side form validation right? And, these validations are always in-sync with the server side validations.
After a bit of cleanup, I’ll commit the code into the Apache MyFaces Sandbox, so you can download it from there when I’m done.
