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();
}
}