3

I have a form that allows the user to optionally enter their zip code. I know how to validate the format of the zip code, by using a @Pattern constraint and regex. But as this is an optional field, I do not want the format validated if it is blank.

How can I tell the system to ignore the @Pattern constraint if the field is blank? This is an optional field and I only want to validate it if it is not blank.

public class MyForm {
    String firstName;
    String lastName;

    @Pattern(regex = "^\d{5}(?:[-\s]\d{4})?$")
    String optionalZipCode;      // <- This is an optional field.
}
vegemite4me
  • 6,621
  • 5
  • 53
  • 79

2 Answers2

9

Hardy's solution does work, but I wanted the declaration to be clearer as regular expressions can take a while to decypher. So I ended up creating my own validator @BlankOrPattern based on @Pattern.

The annotation: BlankOrPattern.java

@Target( {ElementType.FIELD})
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = BlankOrPatternValidator.class)
public @interface BlankOrPattern {
    String regexp();
    Flag[] flags() default {};
    String message() default "{javax.validation.constraints.Pattern.message}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default {};
}

The validator: BlankOrPatternValidator.java

public class BlankOrPatternValidator implements ConstraintValidator<BlankOrPattern, String> {

    private Pattern pattern;

    public void initialize(BlankOrPattern parameters) {
        Flag flags[] = parameters.flags();
        int intFlag = 0;
        for (Flag flag : flags) {
            intFlag = intFlag | flag.getValue();
        }

        try {
            pattern = compile(parameters.regexp(), intFlag);
        } catch (PatternSyntaxException e) {
            throw new IllegalArgumentException("Invalid regular expression.", e);
        }
    }

    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {
        if (value == null || value.length() == 0) {
            return true;
        }
        Matcher m = pattern.matcher(value);
        return m.matches();
    }
}
vegemite4me
  • 6,621
  • 5
  • 53
  • 79
8

You could bake the matching of the empty string into the regular expression. Something like:

"|^\d{5}(?:[-\s]\d{4})?$"

This should match the empty string or your regular expression

Hardy
  • 18,659
  • 3
  • 49
  • 65
  • 1
    I do not like the idea of altering my regular expression to include application logic (e.g. zip code is not required), but your suggestion certainly does work. – vegemite4me Dec 10 '14 at 16:31