I would like to perform validation in some of my input components such as <h:inputText> using some Java bean method. Should I use <f:validator> or <f:validateBean> for this? Where can I read more about it?
I would like to perform validation in some of my input components such as
Share
The standard way is to implement the
Validatorinterface.The
componentargument represents the component to which the validator is attached, which is usually an instance ofUIInput. Thevalueargument represents the value to be validated, which is usually the submitted and converted value of the associatedUIInputcomponent.The
@FacesValidatorwill register it to JSF with validator IDmyValidatorso that you can reference it invalidatorattribute of any<h:inputXxx>/<h:selectXxx>component as follows:If you consider the
valueinvalid, then just throwValidatorException. This way the input field will be marked invalid (i.e.UIInput#isValid()will returnfalse), and the bean property behind thevalueattribute of the input field (the#{bean.foo}) won’t be updated with the submitted/converted value, and the message of theValidatorExceptionwill be displayed in the<h:message>associated with the input field.Do note that checking for null/blank value should be delegated to the
required="true"attribute like so:You can also use EL in
validatorattribute of any<h:inputXxx>/<h:selectXxx>component wherein you reference a managed bean method having exactly the same method signature (the same method arguments) asValidator#validate(). I.e. takingFacesContext,UIComponentandObjectarguments in this order.This is only useful if the validator needs to access another property present in the same managed bean. If it doesn’t need to, then this approach is considered tight-coupling (poor practice thus), and you should split out the validator to its own class implementing the
Validatorinterface.In case you wish to validate based on multiple input values and/or bean properties, much better is to pass them as
<f:attribute>of the component. More detail can be found in the answer to JSF doesn't support cross-field validation, is there a workaround?You can also use
<f:validator>taghandler, which would be the only way if you intend to attach multiple validators on the same component:This will execute the
@FacesValidator("fooValidator")shown above.You can also use
<f:validator binding>to reference a concrete validator instance somewhere in the EL scope, which can be specified and supplied the following way:Note that thus
@Namedis being used instead of@FacesValidator. The old@ManagedBeanis also supported here instead of@Named. Historically, this was a trick in order to be able to use@EJBand@Injectin a validator. See also How to inject in @FacesValidator with @EJB, @PersistenceContext, @Inject, @AutowiredOr this way, which in turn can easily be supplied as a lambda:
Also here applies the same problem of tight-coupling when this validator doesn’t need any other property from the same bean.
To get a step further, you can use JSR303 bean validation. This validates fields based on annotations. So you can have just a
Without the need to explicitly register any validator in XHTML side. If you’re using JPA for persistence, by default this validator will also be executed during insert/update in DB. Since it’s going to be a whole story, here are just some links to get started:
There’s also a
<f:validateBean>tag, but this is only useful if you intend to disable the JSR303 bean validation. You then put the input components (or even the whole form) inside<f:validateBean disabled="true">.