Skip to Main Content

Java EE (Java Enterprise Edition) General Discussion

Announcement

For appeals, questions and feedback about Oracle Forums, please email oracle-forums-moderators_us@oracle.com. Technical questions should be asked in the appropriate category. Thank you!

Cross-Field validation with JSF2 and JSR-303 and h:message

jmsjrNov 20 2012 — edited Dec 5 2012
JSR-303 allows you to do cross-field validation by annotating the class itself instead of annotating a specific property in the backing bean. That is all fine and good, and the validation message is also rendered as part of h:messages.

However, there are some requirements where
1) We need cross-field validation
2) But have the validation message "attached" ( for the lack of a better word ) to a specific property, and thus placed just beside the component in a JSF page.

Using JSR-303 annotations at the class level will NOT show the validation message using <h:message for="xxx"/>, it can only be rendered with <h:messages/>.

For example, some common cross-field validation requirements are:

1) If property A is not null, or is a specific value .. then property B is required.
2) If [1] is true, and B is null or blank, then show the validation message beside the component that is displaying property B.

Since cross-field validation is done with annotations at the class level, and cannot be done at the property level, the validation message for [2] can only be shown with <h:messages/> and not <h:message/>.

To work around this, what I have done is implement a custom (non-JSR303) validator, a javax.faces.validator.Validator, and use that validation in a <f:validator/> tag, as below:
<h:selectOneMenu id="DTHf_causeOfDeath" value="#{insuranceCase.causeOfDeath}" requiredMessage="Cause of Death is required">
	<f:selectItem itemValue="" itemLabel="-Select-" /> 
	<f:selectItems 
			   value="#{facesContext.externalContext.applicationMap['CAUSEOFDTH']}" var="causeOfDeath"
			   itemValue="#{causeOfDeath.code}" 
			   itemLabel="#{causeOfDeath.description}"/>
			   
		   <f:validator validatorId="crossFieldRequiredValidator"/>
		   <f:attribute name="requiredByComponentId" value="caseForm:f_clmTyp"/>
		   <f:attribute name="requiredByComponentValue" value="DTH"/>
</h:selectOneMenu>
The actually validator expects to be supplied:
1) A parameter called "requiredByComponentId", which identifies which other component requires the current component
2) A parameter called "requiredByComponentValue", which specifies the condition or value of the "requiredByComponent" when the current component will be required.

NOTE:
3) I have specified the "requiredMessage" attribute, but NOT the "required" attribute as whether or not it is required is now determined dynamically by the custom validator.
4) The "requiredMessage" attribute is still used by the validator to add the actual message into the FacesContext when creating a FacesMessage.

With this approach, I can now use <h:message/> and have the validation message right beside the component that is dynamically determined to be required.

Though it works, I now have multiple layers of validation: JSR-303 validation and now <f:validator/>. I was hoping that I can use JSR-303 all throughout without having to use <f:validator/>

What have others done in this scenario ?

Edited by: jmsjr on 03-Dec-2012 22:13
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Jan 2 2013
Added on Nov 20 2012
5 comments
1,249 views