有名な話だったらゴメンよ!
Hibernate Validator 先生はめっちゃ便利なわけですが、ある日こんなことが。
「おい! hoge@+gmail.com とか入力されてメール送信系が例外吐いてんぞ! 誰だバリデーションしてねえ馬鹿は!?」
まずそんな馬鹿な作りにしたやつは誰だ。
この時、Hibernate Validator のバージョンは 5.2.2 Final でした。なんで最新じゃないのかって? 知るもんかい。
なお何ら問題なくバリデーションされていた模様
どこを見ても @Validated は付いています。あれ? と思って hoge@!@#$%^&()_+ とかやると……引っかかる。動いてるよなー。
ってことはこいつドメイン部の+通しちまうんじゃねえか!!
なお最新版
5.2.2 で存在した EmailValidator は 最新版 (2018/01/17) では @Deprecated 。では現行はどうなんでしょう?
https://github.com/hibernate/hibernate-validator/blob/7c0afb18cc83aab5e73827a6659af23970dd26f5/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/bv/EmailValidator.java
ありゃ、見当たらない。Abstract の方でしょうか。
DomainNameUtil.isValidEmailDomainAddress( domainPart );
ほうほう、DomainNameUtil 。
private static final String DOMAIN_CHARS_WITHOUT_DASH = "[a-z\u0080-\uFFFF0-9!#$%&'*+/=?^_`{|}~]";
private static final String DOMAIN_LABEL = "(" + DOMAIN_CHARS_WITHOUT_DASH + "-*)*" + DOMAIN_CHARS_WITHOUT_DASH + "+";
private static final String DOMAIN = DOMAIN_LABEL + "+(\\." + DOMAIN_LABEL + "+)*";
デデドン!!(絶望)
……これは参ったなあ。ドメインは RFC1035 ベースで見たほうがいいんじゃないの?って Issue を書くべきかしら。
じゃあ何使えばいいのよ?
Apache commons-validator が割といいらしいっすよ1。
……もっとも、日本語アドレス (Gmailとかは対応してるらしい) みたいなキワモノまで使えるかは試してませんが。
commons-validator ってアノテーションでついてたっけ?
ついてません。さくっとこんな感じで書きませう。
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {CommonsEmailValidator.class})
@Documented
@ReportAsSingleViolation
public @interface Email {
String message() default "{org.hibernate.validator.constraints.Email.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface List {
Email[] value();
}
}
public class CommonsEmailValidator implements ConstraintValidator<Email, String> {
@Override
public void initialize(Email email) {
// nothing to do
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
if( s == null || s.isEmpty() ) return true;
return EmailValidator.getInstance(false).isValid(s);
}
}