Custom JSF validator for required fields
<?xml version='1.0'?> <facelet-taglib version='2.0' ... > <namespace>http://ip.client/ip-jsftoolkit/validator</namespace> <tag> <tag-name>requiredFieldValidator</tag-name> <validator> <validator-id>ip.client.jsftoolkit.RequiredFieldValidator</validator-id> </validator> <attribute> <description>Resource bundle name for the required message</description> <name>bundle</name> <required>false</required> <type>java.lang.String</type> </attribute> <attribute> <description>Key of the required message in the resource bundle</description> <name>key</name> <required>false</required> <type>java.lang.String</type> </attribute> <attribute> <description>Label string for the required message</description> <name>label</name> <required>false</required> <type>java.lang.String</type> </attribute> </tag> </facelet-taglib>
We defined three attributes in order to achieve a high flexibility. A simple using would be
<h:outputLabel for='myInput' value='#{text['myinput']}'/> <h:inputText id='myInput' value='...'> <jtv:requiredFieldValidator label='#{text['myinput']}'/> </h:inputText>
The validator class itself is not difficult. Dependent on the ‘ key’ parameter (key of the required message) and the ‘ label’ parameter (text of the corresponding label) there are four cases how the message gets acquired.
/** * Validator for required fields. */ @FacesValidator(value = RequiredFieldValidator.VALIDATOR_ID) public class RequiredFieldValidator implements Validator { /** validator id */ public static final String VALIDATOR_ID = 'ip.client.jsftoolkit.RequiredFieldValidator'; /** default bundle name */ public static final String DEFAULT_BUNDLE_NAME = 'ip.client.jsftoolkit.validator.message'; private String bundle; private String key; private String label; @Override public void validate(FacesContext facesContext, UIComponent component, Object value) throws ValidatorException { if (!UIInput.isEmpty(value)) { return; } String message; String bundleName; if (bundle == null) { bundleName = DEFAULT_BUNDLE_NAME; } else { bundleName = bundle; } if (key == null && label == null) { message = MessageUtils.getMessageText( MessageUtils.getResourceBundle(facesContext, bundleName), 'jsftoolkit.validator.emptyMandatoryField.1'); } else if (key == null && label != null) { message = MessageUtils.getMessageText( MessageUtils.getResourceBundle(facesContext, bundleName), 'jsftoolkit.validator.emptyMandatoryField.2', label); } else if (key != null && label == null) { message = MessageUtils.getMessageText( MessageUtils.getResourceBundle(facesContext, bundleName), key); } else { message = MessageUtils.getMessageText( MessageUtils.getResourceBundle(facesContext, bundleName), key, label); } throw new ValidatorException(new FacesMessage(FacesMessage.SEVERITY_WARN, message, StringUtils.EMPTY)); // getter / setter ... } }
MessageUtils is an utility class to get ResourceBundle and message text. We also need two text in the resource bundle (property file)
jsftoolkit.validator.emptyMandatoryField.1=Some required field is not filled in. jsftoolkit.validator.emptyMandatoryField.2=The required field '{0}' is not filled in.
and the following context parameter in web.xml
<context-param> <param-name>javax.faces.VALIDATE_EMPTY_FIELDS</param-name> <param-value>true</param-value> </context-param>
This solution is not ideal because we need to define the label text (like #{text[‘myinput’]}) twice and to attach the validator to each field to be validated. A better and generic validator for multiple fields will be presented in the next post. Stay tuned!
Reference: Custom JSF validator for required fields from our JCG partner Oleg Varaksin at the Thoughts on software development blog.