In JSF 2, they added some nifty stuff. One of the items they added was that JSF will seamlessly validate input values using a JSR-303 implementation if one is available. “That’s nifty!” you say, “But how do I get an implementation of JSR-303 into my webapp?”
The reference implementation of JSR-303 is in hibernate validator version 4. What if you don’t want to use hibernate? That’s fine, because the validator project stands alone. You don’t need to use any other parts of hibernate if you don’t want to. Here’s what you should put in your maven pom in order to get hibernate 4 validators.
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>4.0.2.GA</version> </dependency>
Now you should be able to add JSR-303 validators to your project. Something like this should do:
@NotNull @Size(min=3, max=10) private String username;
Now, when you tie an input control to that field in the bean, the value will be validated with the NotNull and Size constraints.
Obviously, the next thought is, “Awesome, now I can easily do multi-field constraints.” For instance, you have a New Password form. You want the user to enter the password, and then to confirm the password. The simple answer is to write a validator that checks that the values of the two fields are equal and place the constraint on the Type, not on the Field. Something like the FieldMatch validator in the answer to this question on stackoverflow would be perfect.
So you implement the FieldMatch validator, and place it on your type. You then deploy your fancy JSF application and test the validator. Strangely your validator is never run. After reading more closely, you discover that JSF does “Field Level” validation using JSR-303 validators. Well, that should be easily enough overcome, right?
Next, you add an f:event tag to the page containing the bean to be validated. The event is preValidate, and you call a method on your bean containing the values. The method you call runs the validator manually. Perfect, right? More testing reveals that the your validator returns true every time, and even more than that, the values it’s testing are both null (which is why they are also equal).
Alright, let’s figure out what’s really going on.
After a half day of reading and testing, you finally go back to JSF basics and remember the JSF lifecycle. Alright, the phases are:
- Restore View
- Apply Request Values
- Process Validations
- Update Model Values
- Invoke Application
- Render Response
Notice that process validations comes before update model values. Well, no wonder putting the type constraint on the bean wasn’t validating the values that were set in the input controls. The values from the controls are validated before they are set on the bean. That explains why JSF 2 only does field level validation. They can take those validators, and apply them to the values that are set on the input controls before they are set in the bean.
So, what’s the answer to this problem? I haven’t decided yet. In this particular case, there are already JSF validators available for just this kind of validation, but what about the general case of type level validators. If I figure anything out, I’ll let you know. If you have any great ideas, chime in on the comments.