Help us understand the problem. What is going on with this article?

Hibernate Validator の @Email を使ってはいけない?

More than 1 year has passed since last update.

有名な話だったらゴメンよ!

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 の方でしょうか。

https://github.com/hibernate/hibernate-validator/blob/35ba4c157e81ce6a54e8717418d2718d384ed144/engine/src/main/java/org/hibernate/validator/internal/constraintvalidators/AbstractEmailValidator.java

DomainNameUtil.isValidEmailDomainAddress( domainPart );

ほうほう、DomainNameUtil 。

https://github.com/hibernate/hibernate-validator/blob/911efbad82d0c81e2ae4aa8b5b412865ed6bd127/engine/src/main/java/org/hibernate/validator/internal/util/DomainNameUtil.java

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);
    }
}
wingsys
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away