JSF Central - Metadata based validation for JavaServer Faces – Part 2
JSF Central

 
 Home 
 
 Products 
 
 Articles & Books 
 
 Resources 
Metadata based validation for JavaServer Faces – Part 2
 
Metadata based validation for JavaServer Faces – Part 2
by Gerhard Petracek
27 Jul 2009 02:00 EDT

In the second article of this series, Gerhard Petracek explains how to replace standard JSF validators with MyFaces ExtVal annotations, and discusses other MyFaces ExtVal annotations that allow you to validate values across input components.


The first part of this series introduced MyFaces ExtVal. We saw that MyFaces ExtVal allows client-side as well as server-side validation, based on validation constraints as well as information provided by JPA annotations. In this part, you’ll learn how to replace standard JSF validators with annotations, and the usage of other MyFaces ExtVal annotations that allow you to validate values across input components. MyFaces ExtVal offers these and other functionalities out-of-the-box, and it’s also possible to provide add-ons for MyFaces ExtVal. We’ll look at one add-on that allows you to bypass validation.

Annotations instead of JSF-Validator-Tags

The examples included in every MyFaces ExtVal release (see binaries and source distributions) as well as the examples at os890 (a Google Code project for open source case and feasibility studies as well as short examples) are a useful reference for learning how to use MyFaces ExtVal. Let’s take a look at the MyFaces ExtVal annotations that replace the standard validator tags of JSF.

The following table shows the standard tags and their annotation replacements:

<f:validateDoubleRange/>

@DoubleRange

<f:validateLength/>

@Length

<f:validateLongRange/>

@LongRange

<f:validator/>

@Validator

@Validator is a type-safe replacement for the standard tag. Instead of the validatorId, you reference the validator class directly. The other annotations just delegate to the default implementations of the equivalent standard JSF validators. If you have registered a custom validator implementation to replace the standard JSF validator, this custom validator is automatically used by MyFaces ExtVal.

Beside these replacements MyFaces ExtVal offers other annotations you can use out of the box. You can find a complete list here. It’s also quite easy to validate custom annotations.

If you look at JSF 1.x validations, you will see that the required attribute of input components is a special case in JSF. In comparison to other currently available validation frameworks for JSF 1.x, MyFaces ExtVal provides @Required as a full replacement for the required attribute (and of course it has some other great features). Furthermore, there are implicit required validations. Figure 1 shows the example from part 1 including the usage of @Length.

  Figure 1 shows a simple entity including MyFaces ExtVal annotations
Figure 1 shows a simple entity including MyFaces ExtVal annotations

If the minimum attribute of @Length is greater than 0 (the default value), the field is automatically required. Since other JSF 1.x validation frameworks still need the required  attribute, they don’t support that (due to the behavior of the standard required validation mechanism). The same applies for @Column(nullable =false), which leads to a required field as well. Also the validation error messages of the standard validators are reused by the default validation strategies of MyFaces ExtVal, so there isn’t a special attribute for a validation error message key. That also means that these validation strategies don’t use the message resolver mechanism of MyFaces ExtVal. If you would like to use message resolving for annotations that replaces the standard JSF validator message resolving mechanism, such as when you have to load messages from an alternative message source like a database, you have to implement custom annotations (which is pretty easy).

Hint: You don’t have to use JPA annotations (the support is optional).
MyFaces ExtVal provides replacements to express the same constraints without JPA annotations. If you don’t like to use the annotations of a JSF centric validation framework within your entities, it’s possible to provide custom annotations. Furthermore, there will be an additional add-on in the os890 project for the next version of MyFaces ExtVal that allows you to provide metadata separately (if the architecture of your application requires such a separation). Since MyFaces ExtVal doesn’t introduce special requirements to annotations, you are free to design them as you prefer. The MyFaces ExtVal documentation and os890 examples show how to implement such custom constraints. In the next part of this article series, we will take a closer look at custom annotations.

Validation without blinders

Standard JSF validation is restricted to input fields. In some cases you need to validate values across different fields. With MyFaces ExtVal, you can easily specify such cross-validations during the validation phase of JSF, saving you a lot of time and effort. Figure 2 shows a very simple case of cross-validation based on the previous example.

  Figure 2 Added cross-validation constraint with simple syntax
Figure 2 Added cross-validation constraint with simple syntax

Here, @NotEquals leads to cross-validation. In this case the first and last names cannot be equal. If a form contains input components which reference both properties (the annotated one and the referenced one), the converted values are used for validation. The minimum requirement for cross-validation is that the property that hosts the cross-validation annotation is bound to an input component of the current form. If the lastName property of the previous example isn’t referenced by an input component of the current form, the model value is used for validation instead. (If you would like to provide a different validation error message in case of such a model-aware cross-validation, it’s possible to provide a so called reverse-violation-message.)

Besides this simple syntax for referencing the target property, you can also use valid EL expressions, as well as local property-chains. This and other concepts are described in the following example:

  Figure 3 Usage of MyFaces ExtVal annotations
Figure 3 Usage of MyFaces ExtVal annotations

Figure 3 shows a backing bean that is used to change a password. That means the user has to enter the old password, which has to be equal to the password stored in the model. In this case an EL expression is used to reference the password property of the person who is referenced in the same class. The oldPassword property hosts @Required. Since the password property of the Person class is required as well, in this scenario this would also be checked implicitly due to @Equals. In this case @Required (and not @Equals) is used to display a required marker, if the used component supports this feature. Furthermore, in this example @NotEquals indicates that the old password has to differ from the new password.

The second property in Figure 3 is the password property. In this case @Equals ensures that the new password is equivalent to the repeated password. Moreover, the property hosts @JoinValidation, which means that all constraints at the referenced target (it’s registrationPage.person.password) are also used for the property hosting the annotation (the registrationPage.password property). In this special scenario you need to use a different password property. If you would bind the password input field directly to the password property of the Person class (registrationPage.person.password), the value of the old password (in this case the obfuscated value) would be displayed instead of an empty input field. In this case you have to provide an additional property to store the password (registrationPage.password). If validation is successful, you can start to process the valid password. As you can see in Figure 3, the final implementation of the action-method is straightforward and you don’t have to worry about cross-validation logic at this point.

The passwordRepeated property illustrates how to provide a custom validation error message via annotations that support the message resolver mechanism. Further details about this mechanism are available at the MyFaces ExtVal Wiki as well as os890.

The implementation of the finish method is quite simple. All validations are performed in the Process Validations phase of JSF. So all constraints have to be valid before the action method gets executed. That’s the reason why you can simply replace the old password of the model with the new password that is stored in the page bean.

As you see in the fragment in figure 4, there is no validation logic required within the page (as always with MyFaces ExtVal).

  Figure 4 The page fragment
Figure 4 The page fragment

Figure 5 shows the rendered page after the user tried to enter a wrong value for the old password.

  Figure 5 The rendered page after cross-validation violation
Figure 5 The rendered page after cross-validation violation

Skipping validation

Sometimes you have to skip validation. In the previous example we have to enter the old password. Let’s assume (just as a simple example) that if a user doesn’t remember the old password, an administrator has to reset this password. You could do that with the same functionality if you add @SkipValidation.

With this annotation all constraints below @SkipValidation are skipped. They are only skipped if at least one of the provided conditions returns true and if the validation strategies for these annotations host @SkipValidationSupport. @SkipValidationSupport for validation strategies doesn’t affect your constraints—it’s possible to register a custom validation strategy which changes this support for an existing constraint. That means that, for instance, validations based on JPA annotations won’t be skipped.

Normally it doesn’t make sense to skip validation for constraints that are defined at the persistence layer. If you do, you won’t be able to save these entities in case of a violation. (While it’s not common, there are special use cases that require you to save an intermediate result temporarily so you can later on persist the final state.) If you would like to change that for the whole application, you can register your custom validation strategy that hosts @SkipValidationSupport (or not). This annotation is included in the property-validation module of MyFaces ExtVal. In the next section you will see a more fine-grained mechanism (provided by an add-on) which allows you to bypass this. The usage of @SkipValidation is illustrated in figure 6:

  Figure 6 Conditional validation
Figure 6 Conditional validation

All constraints you see in this example can be skipped. Every constraint you don’t want to skip has to be placed before @SkipValidation. If you already have information in place which provides the same information as @SkipValidationSupport, MyFaces ExtVal (1.x.2+) provides a new mechanism to reuse this information. As you can see in the news slides of the MyFaces ExtVal 1.x2 release, it’s possible to define custom markers for your validation strategy, or you can register the validation strategy directly.

If you would like to use a more fine grained approach like @MyRequired in figure 7, you have to implement it on your own. However, it isn’t that difficult – I’ll show how to write custom constraints in the next article. Further constraints and add-ons to allow a more fine-grained usage are hosted at os890.

  Figure 7 Custom annotations with fine grained conditions
Figure 7 Custom annotations with fine grained conditions

Bypass validation

Sometimes it’s necessary to bypass all constraints for a special page, or if the user clicks on a special command component. Therefore, the os890 project offers a bypass-validation add-on for MyFaces ExtVal.

Figure 8 shows three action methods with different usages of the bypass-validation add-on. The first action method hosts @BypassValidation. That means a command component bound to this method bypasses all skippable constraints. If you really have to skip all constraints regardless of @SkipValidationSupport, you have to set the all attribute of @BypassValidation to true. You can see an example in the second action method. The last action method of the following example shows a conditional bypass. If at least one of the provided conditions returns true, the bypass validation mechanism is triggered.

  Figure 8 @BypassValidation for action methods
Figure 8 @BypassValidation for action methods

Beside bypassing via action methods, the add-on also offers an annotation which offers a concept similar to view-controller annotations in MyFaces Orchestra and Apache Shale. Figure 9 shows two example usages.

  Figure 9 Two example usages of @BypassValidationController
Figure 9 Two example usages of @BypassValidationController

The first usage of @BypassValidationController means that all skippable constraints are skipped if the value expression uses the registration-page-bean. The second usage means that all constraints are skipped for the /pages/registration.xhtml view-id, if the value expression references the Person object and at least one condition returns true.

Summary

This second part of the MyFaces ExtVal article series shows the easy usage of simple MyFaces ExtVal constraints as well as annotation-based cross-validation. It explains how to skip validation via out-of-the-box mechanisms as well as an alternative approach which is available via a MyFaces ExtVal add-on. This add-on offers an annotation for action methods and one that supports a concept similar to the annotation based view-controller approach. In the next part I'll explain how you can implement custom annotations as well as client-side validation based on annotations.

Resources



RSS feed(all feeds)

The Editor's Desk
Podcasts
Inside Facelets
In the Trenches

Site version 1.83  Report web site problems

Copyright (C) 2003-2014 Virtua, Inc. All Rights Reserved. Java, JavaServer Faces, and all Java-based marks are trademarks or registered trademarks of Oracle Corporation. in the United States and other countries. Virtua, Inc. is independent of Oracle Corporation. All other trademarks are the sole property of their respective owners.