3

For example: I have a JSF Validator to validate e-mail thusly:

@FacesValidator(value="validateEmail")
public class Email implements Validator
{

private static final String EMAIL_REGEXP =
        "^[_A-Za-z0-9-]+(\\.[_A-Za-z0-9-]+)*@[A-Za-z0-9]+(\\.[A-Za-z0-9]+)*(\\.[A-Za-z]{2,})$";

@Override
public void validate(FacesContext context, UIComponent c, Object val) throws ValidatorException
{
    String email = (String) val;
    Pattern mask = null;
    mask = Pattern.compile(EMAIL_REGEXP);
    Matcher matcher = mask.matcher(email);

    if (!matcher.matches()) {
        FacesMessage message = new FacesMessage();
        message.setDetail("Must be of the form xxx@yyy.zzz");
        message.setSummary("E-mail Addresss not valid");
        message.setSeverity(FacesMessage.SEVERITY_ERROR);
        throw new ValidatorException(message);
    }
}
}

This validator will throw an exception if the user doesn't enter an e-mail. However sometimes I want to make the e-mail an optional field. Is there a way to do this that doesn't require me to write a different validator?

Ideally I would like it to check for a parameter somewhere in the JSF markup that uses it.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
AlanObject
  • 9,613
  • 19
  • 86
  • 142

1 Answers1

10

To answer your concrete question, you can make use of <f:attribute> which is enclosed in the same component.

<h:inputText>
    <f:validator validatorId="validateEmail" />
    <f:attribute name="foo" value="bar" />
</h:inputText>

Inside the validate() method it's available by UIComponent#getAttributes() of the 2nd UIComponent argument.

String foo = component.getAttributes().get("foo"); // bar

The better solution in your particular case, however, is just to let the validator return when the value is null or empty.

if (email == null || email.isEmpty()) {
    return;
}

In JSF 1.x this would not be necessary because validators wouldn't be called when the input is null or empty. But in JSF 2.x this has changed in order to support JSR303 bean validation. So if you want to skip validation on empty fields, you'd need to check this in every single JSF Validator.

Note that when you have this in your web.xml

<context-param>
    <param-name>javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL</param-name>
    <param-value>true</param-value>
</context-param>

then you can safely omit the email.isEmpty() part from the check because it would always be null instead of an empty string.


Unrelated to the concrete problem, the pattern which you've there is outdated. These days unicode characters are allowed in email addresses.

private static final String EMAIL_REGEXP = "([^.@]+)(\\.[^.@]+)*@([^.@]+\\.)+([^.@]+)";

(note that ^ and $ are unnecessary because Pattern implicitly uses this already)

Further I also suggest to do the Pattern#compile() directly on a static final variable. Compiling a pattern is relatively expensive and a Pattern instance is threadsafe anyway.

private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEXP);
Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • OK I got this to work and it seems simple enough. One caveat, though make sure that your invented attribute doesn't match something the taglib already has! For example ** – AlanObject Jan 20 '12 at 19:59
  • Thanks for the tip on e-mail. I knew that but I had copied this pattern off some web page written last century and haven't gotten around to fixing it. – AlanObject Jan 20 '12 at 20:00
  • P.S. My example was for a "required" field but I want to use this technique for non-trivial options and it will be quite useful for that. Thanks again. – AlanObject Jan 20 '12 at 20:01
  • You're welcome. Indeed, it may not collide with any of existing attribtues which serves a different purpose. You can however use it to set or *override* an existing attribute. This is useful if you want conditional attributes. E.g. ``. – BalusC Jan 20 '12 at 20:01
  • @BalusC thank you! So many useful answers. Clear and straight to the point. – Kristijan Iliev Feb 05 '16 at 12:02