Bean検証における@NotNull、@NotEmpty、および@NotBlankの制約の違い

1概要

Bean Validation ** は、アノテーションの形で宣言された一連の制約を使用してドメインオブジェクトを簡単に検証できるようにする標準の検証仕様です。

全体としては、http://hibernate.org/validator/[Hibernate Validator]などのBean検証実装の使用はかなり簡単ですが、これらの制約のいくつかがどのように実装されているかに関して、微妙ではあるが適切な違いを検討する価値があります。

このチュートリアルでは、 NotNull @ NotEmpty、 @ NotBlank__の制約の違いについて説明します。

2 Mavenの依存関係

作業環境を素早くセットアップし、 @ NotNull @ NotEmpty 、および @ NotBlank の制約の動作をテストするには、まず必要なMavenの依存関係を追加する必要があります。

この場合、ドメインオブジェクトの検証には、http://hibernate.org/validator/[Hibernate Validator]というBean検証参照実装を使用します。

これが pom.xml ファイルの関連セクションです。

<dependencies>
    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.13.Final</version>
    </dependency>
    <dependency>
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.0</version>
     </dependency>
</dependencies>

我々のユニットテストではhttps://junit.org/junit5/[JUnit]とhttp://joel-costigliola.github.io/assertj/[AssertJ]を使用するので、httpsの最新版を確認してください。 ://search.maven.org/search?q = g:org.hibernate%20AND%20a:hibernate-validator

3 @ NotNull 制約

先に進んで、素朴な UserNotNull ドメインクラスとその name フィールドに @ NotNull アノテーションを付けて実装しましょう。

public class UserNotNull {

    @NotNull(message = "Name may not be null")
    private String name;

   //standard constructors/getters/toString
}

それでは、 @ NotNull が実際にはどのように機能するのかを確認する必要があります。 __

そうするために、クラスのための簡単な単体テストを作成し、それのいくつかのインスタンスを検証しましょう:

@BeforeClass
public static void setupValidatorInstance() {
    validator = Validation.buildDefaultValidatorFactory().getValidator();
}

@Test
public void whenNotNullName__thenNoConstraintViolations() {
    UserNotNull user = new UserNotNull("John");
    Set<ConstraintViolation<UserNotNull>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(0);
}

@Test
public void whenNullName__thenOneConstraintViolation() {
    UserNotNull user = new UserNotNull(null);
    Set<ConstraintViolation<UserNotNull>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(1);
}

@Test
public void whenEmptyName__thenNoConstraintViolations() {
    UserNotNull user = new UserNotNull("");
    Set<ConstraintViolation<UserNotNull>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(0);
}

予想されたように、 @ NotNull 制約は制約されたフィールドにnull値を許可しませんでした。それでも、フィールドは空になることがあります。

これをよりよく理解するために、http://docs.jboss.org/ejb3/app-server/HibernateAnnotations/api/org/hibernate/validator/NotNullValidator.html#isV​​alid(java.lang.Object)[ NotNullValidator クラスを見てみましょう。 @ NotNull 制約が使用する isValid() メソッド。メソッドの実装は本当に簡単です。

public boolean isValid(Object object) {
    return object != null;
}

上記のように、 @ NotNull で制約されたフィールド( CharSequence Collection Map、 、または Arrayなど)はnullであってはなりません。しかしながら、空の値は完全に合法的です

4 @ NotEmpty 制約

それでは、サンプル UserNotEmpty クラスを実装し、 @ NotEmpty 制約を使用しましょう。

public class UserNotEmpty {

    @NotEmpty(message = "Name may not be empty")
    private String name;

   //standard constructors/getters/toString
}

クラスを設定したら、 name フィールドに異なる値を割り当ててテストしましょう。

@Test
public void whenNotEmptyName__thenNoConstraintViolations() {
    UserNotEmpty user = new UserNotEmpty("John");
    Set<ConstraintViolation<UserNotEmpty>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(0);
}

@Test
public void whenEmptyName__thenOneConstraintViolation() {
    UserNotEmpty user = new UserNotEmpty("");
    Set<ConstraintViolation<UserNotEmpty>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(1);
}

@Test
public void whenNullName__thenOneConstraintViolation() {
    UserNotEmpty user = new UserNotEmpty(null);
    Set<ConstraintViolation<UserNotEmpty>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(1);
}

@ NotEmpty アノテーションは @ NotNull クラスの isValid() 実装を利用し、さらに提供されたオブジェクトのサイズ/長さ(もちろん検証されるオブジェクトの種類によって異なります)がゼロより大きいことを確認します。

一言で言えば、** これは、 @ NotEmpty で制約されたフィールド( CharSequence Collection Map、 、または__Arrayなど)がnullであってはならず、サイズ/長さがゼロより大きくなければならないことを意味します

さらに、 @ NotEmpty アノテーションを @Size. と共に使用すると、さらに制限が厳しくなります。

その際、オブジェクトの最小サイズと最大サイズの値が指定された最小/最大範囲内になるように強制します。

@NotEmpty(message = "Name may not be empty")
@Size(min = 2, max = 32, message = "Name must be between 2 and 32 characters long")
private String name;

5 @ NotBlank 制約

同様に、 @ NotBlank アノテーションを使ってクラスフィールドを制約することができます。

public class UserNotBlank {

    @NotBlank(message = "Name may not be blank")
    private String name;

   //standard constructors/getters/toString

}

同様に、 @ NotBlank 制約がどのように機能するのかを理解するための単体テストを実装することができます。

@Test
public void whenNotBlankName__thenNoConstraintViolations() {
    UserNotBlank user = new UserNotBlank("John");
    Set<ConstraintViolation<UserNotBlank>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(0);
}

@Test
public void whenBlankName__thenOneConstraintViolation() {
    UserNotBlank user = new UserNotBlank(" ");
    Set<ConstraintViolation<UserNotBlank>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(1);
}

@Test
public void whenEmptyName__thenOneConstraintViolation() {
    UserNotBlank user = new UserNotBlank("");
    Set<ConstraintViolation<UserNotBlank>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(1);
}

@Test
public void whenNullName__thenOneConstraintViolation() {
    UserNotBlank user = new UserNotBlank(null);
    Set<ConstraintViolation<UserNotBlank>> violations = validator.validate(user);

    assertThat(violations.size()).isEqualTo(1);
}

@ NotBlank アノテーションはhttps://docs.jboss.org/hibernate/validator/6.0/api/org/hibernate/validator/internal/constraintvalidators/hv/NotBlankValidator.html[ NotBlankValidator ]クラスを使用してその文字をチェックしますシーケンスのトリミングされた長さは空ではありません。

public boolean isValid(
  CharSequence charSequence,
  ConstraintValidatorContext constraintValidatorContext)
    if (charSequence == null ) {
        return true;
    }
    return charSequence.toString().trim().length() > 0;
}

面白いことに、このメソッドはnull値に対してtrueを返します。そのため、 @ NotBlank ではNULL値が許可されていると思われるかもしれませんが、実際には許可されていません。

  • @ NotNull クラスのisValid()メソッドは、 @ NotBlank クラスのisValid()の後に呼び出されるため、NULL値は禁止されます。

簡単に言うと、 @ NotBlank で制約された String フィールドはNULLではなく、トリミングされた長さはゼロより大きくなければなりません** 。

6. 並列比較

これまで、 @ NotNull @ NotEmpty 、および @ NotBlank の制約がクラスフィールドに対してどのように機能するのかについて詳しく説明しました。

簡単に並べて比較してみましょう。そうすれば、制約の機能を鳥瞰図で確認でき、それらの違いを簡単に見つけることができます。

  • @ NotNull: 制約のある CharSequence Collection Map、 または

Array はnullではない限り有効ですが、空でもかまいません ** @ NotEmpty: 制約のある CharSequence Collection Map、 、または

Array は、nullでなく、サイズ/長さがそれより大きい限り有効です。 ゼロより ** @ NotBlank: 制約のある String はnullでない限り有効です

そしてトリミングされた長さはゼロより大きいです

7. 結論

この記事では、Bean Validationに実装されている NotNull @ NotEmpty 、および @ NotBlank の制約を調べ、それらの類似点と相違点を強調しました。

いつものように、この記事に示されているすべてのコードサンプルはhttps://github.com/eugenp/tutorials/tree/master/javaxval[GitHubで利用可能]です。