DigitalJoel

2010/04/12

JSF 2, JSR-303, and you

Filed under: development, java, JSF, JSF2 — Tags: , — digitaljoel @ 9:21 pm

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:

  1. Restore View
  2. Apply Request Values
  3. Process Validations
  4. Update Model Values
  5. Invoke Application
  6. 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.

Advertisements

5 Comments »

  1. Every time I read your blog, I am gratefully reminded of how much I really prefer the Python work I am doing now. 🙂

    Comment by Travis Jensen — 2010/04/12 @ 10:13 pm

  2. RichFaces requires the object to be Cloneable, makes a deep copy, simulates the update model phase on the copied model, runs validation, then throws away the copy. Seems like that’s the only way to do the validation correctly before Update Model. (I’d be willing to live with validation after Update Model, the problem being invalid values are not rolled back.)

    Problem is, RichFaces ignores the “path” returned by validation constraints, so fields are not highlighted. (The FieldMatchValidator example could be extended to add ‘secondFieldName’ to the message’s path.) (Similar question here: http://stackoverflow.com/questions/5639088/cross-field-validation-with-inline-messaging-in-jsf-with-jsr-303)

    I’ve been thinking, if only I could extend the GraphValidator implementation:
    – create a subclass of FacesMessage that holds the ConstraintViolation
    – update (the per-field validation tag) to look for the custom FacesMessages whose rootBean and path match the field’s EL expression, call setValid(false) and re-associate the message to the field’s ID

    Does that make sense and if so, do you think we could make it reality?

    Comment by Peter Davis — 2011/04/13 @ 9:38 am

    • I haven’t worked with RichFaces, but the way they implemented it is kind of what I was thinking would have to be done in order to get it working. Doesn’t seem very pretty to me, but I’m not sure how else they could get it into the lifecycle. That’s a shame they ignore the path. I also haven’t played with the GraphValidator so I won’t have any good input for you there.

      Since writing this post I have changed projects and we opted for Spring MVC rather than JSF in that project. I completed that project and have since changed jobs. I am also part of a startup, working nights and weekends, and also using Spring MVC there. So based on my extremely cramped schedule I don’t think “we” could make it a reality if that includes me, but based on your summary above you sound more than capable of getting it done 🙂

      Comment by digitaljoel — 2011/04/13 @ 12:44 pm

  3. Have you found solution for this problem? I just got to the same trubles! Thanks!

    Comment by Lukas Camra — 2012/06/26 @ 4:06 pm

    • Sorry for you, but fortunately for me my solution was to leave JSF and move on to something else. I haven’t really worked in JSF for nearly 2 years. I would hope they have come up with a solution in that time, but I couldn’t point you to it.

      Comment by digitaljoel — 2012/06/28 @ 8:41 am


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.