1前書き

この記事では、


Apache BVal

ライブラリーの

Java Bean Validation

specification(

JSR 349



の実装を見ていきます。


2 Mavenの依存関係


Apache BVal

を使用するには、まず

pom.xml

ファイルに次の依存関係を追加する必要があります。

<dependency>
    <groupId>org.apache.bval</groupId>
    <artifactId>bval-jsr</artifactId>
    <version>1.1.2</version>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>

カスタムの

BVal

制約は、オプションの

bval-extras

依存関係にあります。

<dependency>
    <groupId>org.apache.bval</groupId>
    <artifactId>bval-extras</artifactId>
    <version>1.1.2</version>
</dependency>


bval-jsr

、https://search.maven.org/classic/の最新バージョン#search%7Cga%7C1%7Capache%20bval%20extras[bval-extras]、およびhttps://search.maven.org/classic/#search%7Cga%7C1%7Cg%3A%22javax.validation%22 api]はMaven Centralからダウンロードできます。


3制約を適用する


Apache BVal

は、

javax.validation

パッケージで定義されているすべての制約に対する実装を提供します。 Beanのプロパティに制約を適用するために、制約宣言をプロパティ宣言に追加することができます。

4つの属性を持つ

User

クラスを作成してから、

@ NotNull



@ Size

、および

@ Min

の注釈を適用します。

public class User {

    @NotNull
    private String email;

    private String password;

    @Size(min=1, max=20)
    private String name;

    @Min(18)
    private int age;

   //standard constructor, getters, setters
}


4検証Bean


User

クラスに適用された制約を検証するには、

ValidatorFactory

インスタンスと1つ以上の

Validator

インスタンスを取得する必要があります。


4.1.

ValidatorFactory


を取得する


Apache BVal

ドキュメントでは、このクラスの単一のインスタンスを取得することが推奨されています。ファクトリの作成は大変なプロセスです。

ValidatorFactory validatorFactory
  = Validation.byProvider(ApacheValidationProvider.class)
  .configure().buildValidatorFactory();


4.2.

Validator


を取得する

次に、上で定義された

validatorFactory

から

Validator

インスタンスを取得する必要があります。

Validator validator = validatorFactory.getValidator();

  • これはスレッドセーフな実装です** ので、作成済みのインスタンスを安全に再利用できます。


Validator

クラスは、Beanの有効性を判断するための3つのメソッドを提供します。

これらの各メソッドは、従わなかった制約に関する情報を含む

ConstraintViolation

オブジェクトのセットを返します。


4.3.

validate()

API


validate()

メソッドは、Bean全体の有効性をチェックします。つまり、パラメータとして渡されたオブジェクトのプロパティに適用されているすべての制約が検証されます。


User

オブジェクトを定義し、そのプロパティをテストするために

validate()

メソッドを使用する

JUnit

テストを作成しましょう。

@Test
public void givenUser__whenValidate__thenValidationViolations() {
    User user
      = new User("[email protected]", "pass", "nameTooLong______________________________", 15);

    Set<ConstraintViolation<User>> violations = validator.validate(user);
    assertTrue("no violations", violations.size() > 0);
}


4.4.

validateProperty()

API


validateProperty()

メソッドを使用して、Beanの単一のプロパティを検証することができます。

必要な最小値18未満の

age

プロパティを持つ

User

オブジェクトを定義し、このプロパティを検証すると1つの違反が発生することを確認する

JUnit

テストを作成しましょう。

@Test
public void givenInvalidAge__whenValidateProperty__thenConstraintViolation() {
    User user = new User("[email protected]", "pass", "Ana", 12);

    Set<ConstraintViolation<User>> propertyViolations
      = validator.validateProperty(user, "age");

    assertEquals("size is not 1", 1, propertyViolations.size());
}


4.5.

validateValue()

API


validateValue()

メソッドは、Beanに設定する前に、ある値がBeanのプロパティに対して有効な値であるかどうかをチェックするために使用できます。


User

オブジェクトを使用して

JUnit

テストを作成し、値

20



age

プロパティの有効な値であることを確認します。

@Test
public void givenValidAge__whenValidateValue__thenNoConstraintViolation() {
    User user = new User("[email protected]", "pass", "Ana", 18);

    Set<ConstraintViolation<User>> valueViolations
      = validator.validateValue(User.class, "age", 20);

    assertEquals("size is not 0", 0, valueViolations.size());
}


4.6.

ValidatorFactory


を閉じる


  • ValidatorFactory

    を使用した後は、最後に** 閉じる必要があります。

if (validatorFactory != null) {
    validatorFactory.close();
}


5

JSR

以外の制約


Apache BVal

ライブラリはまた、

JSR

仕様の一部ではない** 一連の制約を提供し、追加のより強力な検証機能を提供します。


bval-jsr

パッケージには、2つの追加の制約が含まれています。有効な電子メールアドレスを検証するための

@ Email

と、値が空でないことを確認するための

@ NotEmpty

です。

カスタムの

BVal

制約の残りは、オプションのパッケージ

bval-extras

で提供されています。

このパッケージには、数字が有効な国際銀行口座番号であることを保証する

@ IBAN

注釈、有効な標準図書番号を検証する

@ Isbn

注釈、国際商品番号の確認

このライブラリーはまた、さまざまなタイプのクレジットカード番号の有効性を保証するためのアノテーションも提供しています。


@ Domain

および

@ InetAddress

アノテーションを使用して、値に有効なドメインまたはインターネットアドレスが含まれているかどうか** を判断できます。

そして最後に、このパッケージには、

File

オブジェクトがディレクトリかどうかを検証するための

@ Directory

および

@ NotDirectory

アノテーションが含まれています。


User

クラスで追加のプロパティを定義し、それらに

JSR

以外のアノテーションをいくつか適用しましょう。

public class User {

    @NotNull
    @Email
    private String email;

    @NotEmpty
    private String password;

    @Size(min=1, max=20)
    private String name;

    @Min(18)
    private int age;

    @Visa
    private String cardNumber = "";

    @IBAN
    private String iban = "";

    @InetAddress
    private String website = "";

    @Directory
    private File mainDirectory = new File(".");

   //standard constructor, getters, setters
}

制約は

JSR

制約と同様にテストできます。

@Test
public void whenValidateNonJSR__thenCorrect() {
    User user = new User("[email protected]", "pass", "Ana", 20);
    user.setCardNumber("1234");
    user.setIban("1234");
    user.setWebsite("10.0.2.50");
    user.setMainDirectory(new File("."));

    Set<ConstraintViolation<User>> violations
      = validator.validateProperty(user,"iban");

    assertEquals("size is not 1", 1, violations.size());

    violations = validator.validateProperty(user,"website");

    assertEquals("size is not 0", 0, violations.size());

    violations = validator.validateProperty(user, "mainDirectory");

    assertEquals("size is not 0", 0, violations.size());
}

これらの追加のアノテーションは潜在的な検証のニーズには便利ですが、

JSR

仕様の一部ではないアノテーションを使用することの1つの欠点は、後で必要になった場合に別の

JSR

実装に簡単に切り替えることができないことです。


6. カスタム制約

独自の制約を定義するためには、まず標準の構文に従って注釈を作成する必要があります。

ユーザーのパスワードが満たすべき条件を定義する

Password

アノテーションを作成しましょう。

@Constraint(validatedBy = { PasswordValidator.class })
@Target({METHOD, FIELD, ANNOTATION__TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface Password {
    String message() default "Invalid password";

    Class<?>[]groups() default {};

    Class<? extends Payload>[]payload() default {};

    int length() default 6;

    int nonAlpha() default 1;
}


  • password

    値の実際の検証は、

    ConstraintValidator

    インターフェースを実装するクラス** – 私たちの場合は

    PasswordValidator

    クラスで行われます。このクラスは

    isValid()

    メソッドをオーバーライドし、

    password

    の長さが

    length

    属性より短いかどうか、および

    nonAlpha

    属性に指定された数より少ない英数字以外の文字が含まれるかどうかを検証します。

public class PasswordValidator
  implements ConstraintValidator<Password, String> {

    private int length;
    private int nonAlpha;

    @Override
    public void initialize(Password password) {
        this.length = password.length();
        this.nonAlpha = password.nonAlpha();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext ctx) {
        if (value.length() < length) {
            return false;
        }
        int nonAlphaNr = 0;
        for (int i = 0; i < value.length(); i++) {
            if (!Character.isLetterOrDigit(value.charAt(i))) {
                nonAlphaNr++;
            }
        }
        if (nonAlphaNr < nonAlpha) {
            return false;
        }
        return true;
    }
}

カスタム制約を

User

クラスの

password

プロパティに適用しましょう。

@Password(length = 8)
private String password;


JUnit

テストを作成して、無効な

password

値が制約違反になることを確認できます。

@Test
public void givenValidPassword__whenValidatePassword__thenNoConstraintViolation() {
    User user = new User("[email protected]", "password", "Ana", 20);
    Set<ConstraintViolation<User>> violations
      = validator.validateProperty(user, "password");

    assertEquals(
      "message incorrect",
      "Invalid password",
      violations.iterator().next().getMessage());
}

それでは、有効な

password

値を検証する

JUnit

テストを作成しましょう。

@Test
public void givenValidPassword__whenValidatePassword__thenNoConstraintViolation() {
    User user = new User("[email protected]", "password#", "Ana", 20);

    Set<ConstraintViolation<User>> violations
      = validator.validateProperty(user, "password");
    assertEquals("size is not 0", 0, violations.size());
}


7. 結論

この記事では、

Apache BVal

bean検証実装の使用法を例示しました。

この記事の完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/apache-bval[over on GitHub]にあります。