13.2. バリデーション制約
13.2.1. バリデーション制約
バリデーション制約とは、フィールド、プロパティー、Bean などの Java 要素に適用するルールのことです。制約は通常、制限を設定する際に利用する一連の属性です。定義済みの制約がありますが、カスタムの制約も作成可能です。各制約は、アノテーション形式で表されます。
Hibernate Validator 用の同梱のバリデーション制約は、Hibernate Validator の制約 にリストされています。
13.2.2. Hibernate Validator の制約
該当する場合は、アプリケーションレベルの制約により、以下の表の Hibernate Metadata Impact 列で説明されているデータベースレベルの制約が作成されます。
Java 固有のバリデーション制約
以下の表には、javax.validation.constraints
パッケージに含まれる Java 仕様で定義されたバリデーション制約が示されています。
アノテーション | プロパティータイプ | ランタイムチェック | Hibernate Metadata の影響 |
---|---|---|---|
@AssertFalse | ブール値 | メソッドが false に評価されていることを確認します。アノテーションではなくコードで表現される制約に便利です。 | なし |
@AssertTrue | ブール値 | メソッドが true に評価されていることを確認します。アノテーションではなくコードで表現される制約に便利です。 | なし |
@Digits(integerDigits=1) | 数値または数値の文字列表現 |
プロパティーが | カラムの精度とスケールを定義します。 |
@Future | 日付またはカレンダー | 未来の日付であるかを確認します。 | なし |
@Max(value=) | 数値または数値の文字列表現 | 値が最大値以下であるかを確認します。 | カラムに check 制約を追加します。 |
@Min(value=) | 数値または数値の文字列表現 | 値が最小値以上であるかを確認します。 | カラムに check 制約を追加します。 |
@NotNull | 値が null でないかを確認します。 | カラムが null でないかを確認します。 | |
@Past | 日付またはカレンダー | 過去の日付であるかを確認します。 | カラムに check 制約を追加します。 |
@Pattern(regexp="regexp", flag=) or @Patterns( {@Pattern(…)} ) | String |
プロパティーが一致フラグが指定された正規表現に一致するかどうかを確認します。 | なし |
@Size(min=, max=) | アレイ、コレクション、マップ | 要素サイズが最小値以上で最大値以下であるかどうかを確認します。 | なし |
@Valid | オブジェクト | 紐付けされたオブジェクトに再帰的にバリデーションを実行します。オブジェクトがコレクションかアレイの場合は、要素は再帰的に検証されます。また、オブジェクトがマップの場合、値要素が再帰的に検証されます。 | なし |
パラメーター @Valid
は、javax.validation.constraints
パッケージに存在しますが Jakarta Bean Validation 仕様の一部です。
Hibernate Validator 固有のバリデーション制約
以下の表には、org.hibernate.validator.constraints
パッケージに含まれるベンダー固有のバリデーション制約が含まれます。
アノテーション | プロパティータイプ | ランタイムチェック | Hibernate Metadata の影響 |
---|---|---|---|
@Length(min=, max=) | String | 文字列の長さが指定の範囲と一致するかを確認します。 | カラムの長さを最大に設定します。 |
@CreditCardNumber | String | 文字列が正規の形式のクレジットカード番号であるかどうかを確認します (Luhn アルゴリズムの派生)。 | なし |
@EAN | String | 文字列が正しくフォーマットされた EAN あるいは UPC-A コードであるかを確認します。 | なし |
| String | 文字列がメールアドレスの仕様に準拠するかどうかを確認します。 | なし |
@NotEmpty | 文字列が null あるいは空でないかを確認します。接続が null あるいは空でないかを確認します。 | カラムは文字列の null ではありません。 | |
@Range(min=, max=) | 数値または数値の文字列表現 | 値が最小値以上で最大値以下であるかどうかを確認します。 | カラムに check 制約を追加します。 |
13.2.3. Jakarta Bean Validation カスタム制約の使用
Jakarta Bean Validation API は、@NotNull
や @Size
などの標準の制約アノテーションのセットを定義します。しかし、これらの事前定義された制約が十分でない場合、バリデーションの要件に合ったカスタム制約を簡単に作成できます。
Jakarta Bean Validation を作成する場合、カスタム制約には 制約アノテーションの作成 と 制約バリデーターの実装 が必要になります。以下のコードサンプルは、JBoss EAP に同梱される bean-validation-custom-constraint
クイックスタートから抜粋したものです。完全な作業例はこのクイックスタートを参照してください。
13.2.3.1. 制約アノテーションの作成
以下は、AddressValidator
クラスで定義されたカスタム制約のセットを使用して、エンティティー Person
の personAddress
フィールドがバリデーションされる例を表しています。
エンティティー
Person
を作成します。例:
Person
クラスpackage org.jboss.as.quickstarts.bean_validation_custom_constraint; @Entity @Table(name = "person") public class Person implements Serializable { private static final long serialVersionUID = 1L; @Id @GeneratedValue @Column(name = "person_id") private Long personId; @NotNull @Size(min = 4) private String firstName; @NotNull @Size(min = 4) private String lastName; // Custom Constraint @Address for bean validation @NotNull @Address @OneToOne(mappedBy = "person", cascade = CascadeType.ALL) private PersonAddress personAddress; public Person() { } public Person(String firstName, String lastName, PersonAddress address) { this.firstName = firstName; this.lastName = lastName; this.personAddress = address; } /* getters and setters omitted for brevity*/ }
制約バリデーターファイルを作成します。
例:
Address
インターフェイスpackage org.jboss.as.quickstarts.bean_validation_custom_constraint; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import javax.validation.Constraint; import javax.validation.Payload; // Linking the AddressValidator class with @Address annotation. @Constraint(validatedBy = { AddressValidator.class }) // This constraint annotation can be used only on fields and method parameters. @Target({ ElementType.FIELD, ElementType.PARAMETER }) @Retention(value = RetentionPolicy.RUNTIME) @Documented public @interface Address { // The message to return when the instance of MyAddress fails the validation. String message() default "Address Fields must not be null/empty and obey character limit constraints"; Class<?>[] groups() default {}; Class<? extends Payload>[] payload() default {}; }
例:
PersonAddress
クラスpackage org.jboss.as.quickstarts.bean_validation_custom_constraint; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToOne; import javax.persistence.PrimaryKeyJoinColumn; import javax.persistence.Table; @Entity @Table(name = "person_address") public class PersonAddress implements Serializable { private static final long serialVersionUID = 1L; @Id @Column(name = "person_id", unique = true, nullable = false) @GeneratedValue(strategy = GenerationType.SEQUENCE) private Long personId; private String streetAddress; private String locality; private String city; private String state; private String country; private String pinCode; @OneToOne @PrimaryKeyJoinColumn private Person person; public PersonAddress() { } public PersonAddress(String streetAddress, String locality, String city, String state, String country, String pinCode) { this.streetAddress = streetAddress; this.locality = locality; this.city = city; this.state = state; this.country = country; this.pinCode = pinCode; } /* getters and setters omitted for brevity*/ }
13.2.3.2. 制約バリデーターの実装
アノテーションを定義したら、@Address
アノテーションが付けられた要素のバリデーションが可能な制約バリデーターを作成する必要があります。これには、以下のように ConstraintValidator
インターフェイスを実装します。
例: AddressValidator
クラス
package org.jboss.as.quickstarts.bean_validation_custom_constraint; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import org.jboss.as.quickstarts.bean_validation_custom_constraint.PersonAddress; public class AddressValidator implements ConstraintValidator<Address, PersonAddress> { public void initialize(Address constraintAnnotation) { } /** * 1. A null address is handled by the @NotNull constraint on the @Address. * 2. The address should have all the data values specified. * 3. Pin code in the address should be of at least 6 characters. * 4. The country in the address should be of at least 4 characters. */ public boolean isValid(PersonAddress value, ConstraintValidatorContext context) { if (value == null) { return true; } if (value.getCity() == null || value.getCountry() == null || value.getLocality() == null || value.getPinCode() == null || value.getState() == null || value.getStreetAddress() == null) { return false; } if (value.getCity().isEmpty() || value.getCountry().isEmpty() || value.getLocality().isEmpty() || value.getPinCode().isEmpty() || value.getState().isEmpty() || value.getStreetAddress().isEmpty()) { return false; } if (value.getPinCode().length() < 6) { return false; } if (value.getCountry().length() < 4) { return false; } return true; } }