第13章 Jakarta Bean Validation
13.1. Jakarta Bean Validation について
Jakarta Bean Validation は、Java オブジェクトのデータを検証するモデルです。このモデルでは、組み込みのカスタムアノテーション制約を使い、アプリケーションデータの整合性を保ちます。また、メソッドおよびコンストラクターバリデーションも提供し、パラメーターおよび戻り値の制約を確保します。この仕様は、Jakarta Bean Validation 2.0 仕様で文書化されています。
Hibernate Validator は Jakarta Bean Validation の JBoss EAP 実装です。Jakarta Bean Validation 2.0 仕様のリファレンス実装でもあります。
JBoss EAP は Jakarta Bean Validation 2.0 仕様に完全準拠しています。また、Hibernate Validator によってこの仕様に追加機能が提供されます。
Jakarta Bean Validation を初めて使用する場合は、JBoss EAP に同梱された bean-validation
クイックスタートを参照してください。クイックスタートをダウンロードし、実行する方法は、JBoss EAP『スタート ガイド』 の「クイックスタートサンプルの使用 」を参照してください。
JBoss EAP 7.4 には Hibernate Validator 6.0.x が含まれるようになりました。
Hibernate Validator 6.0.x の新機能
Jakarta Bean Validation 2.0 はエンティティーおよびメソッドバリデーションのメタデータモデルおよび API を定義します。
メタデータのデフォルトのソースはアノテーションで、XML を使用してメタデータをオーバーライドおよび拡張することができます。
API は特定のアプリケーション階層やプログラミングモデルに関係しません。サーバー側のアプリケーションプログラミングとリッチクライアント Swing アプリケーションの開発の両方で利用できます。
- 本リリースの Hibernate Validator は、バグ修正が含まれるだけでなく、最も一般的なユースケースに対してパフォーマンスが向上されています。
- Jakarta Bean Validation はバージョン 1.1 より、Jakarta Bean Validation API を使用して任意 Java タイプのメソッドのパラメーターおよび戻り値に制約も適用できるようになりました。
Hibernate Validator 6.0.x および Jakarta Bean Validation 2.0 には Java 8 以上が必要になります。
詳細は、『Hibernate Validator 6.0.17.Final - JSR 380 Reference Implementation: Reference Guide』を参照してください。
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; } }
13.3. Jakarta Bean Validation 設定
Jakarta Bean Validation は、/META-INF
ディレクトリーにある validation.xml
ファイル内の XML を使用して設定できます。このファイルがクラスパスに存在する場合は、ValidatorFactory
が作成されたときに設定が適用されます。
例: Jakarta Bean Validation 設定ファイル
以下の例は、validation.xml
ファイルの複数の設定オプションを示しています。これらすべての設定はオプションです。これらのオプションは、javax.validation
パッケージを使用して設定することもできます。
<validation-config xmlns="http://jboss.org/xml/ns/javax/validation/configuration" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/configuration"> <default-provider> org.hibernate.validator.HibernateValidator </default-provider> <message-interpolator> org.hibernate.validator.messageinterpolation.ResourceBundleMessageInterpolator </message-interpolator> <constraint-validator-factory> org.hibernate.validator.engine.ConstraintValidatorFactoryImpl </constraint-validator-factory> <constraint-mapping> /constraints-example.xml </constraint-mapping> <property name="prop1">value1</property> <property name="prop2">value2</property> </validation-config>
ノード default-provider
では、Jakarta Bean Validation プロバイダーを選択できます。これは、クラスパスに複数のプロバイダーがある場合に役に立ちます。message-interpolator
プロパティーと constraint-validator-factory
プロパティーは、javax.validation
パッケージで定義されたインターフェース MessageInterpolator
および ConstraintValidatorFactory
の使用済み実装をカスタマイズするために使用されます。constraint-mapping
要素は、実際の制約設定が含まれる追加の XML ファイルをリストします。