The Java EE 7 Tutorialの21 Introduction to Bean Validationの章をテキトーに訳した。
21 Introduction to Bean Validation
データの整合性を維持するためにユーザの入力値を検証することはアプリケーションロジックの重要な部分です。データの検証は、Developing a Simple Facelets Application: The guessnumber-jsf Example Applicationなどの、シンプルなアプリケーションでさえ異なるレイヤーで現れます。guessnumber-jsf
サンプルアプリケーションは、プレゼンテーションレイヤーでユーザ入力(h:inputText
タグ)の数値データ検証を行い、ビジネスレイヤーで数値の範囲検証を行います。
Java API for JavaBean Validation ("Bean Validation")は、オブジェクト・オブジェクトのメンバ・メソッド・コンストラクタの検証機能を提供します。Java EE環境では、Bean ValidationはJava EEコンテナとサービスに統合されており、開発者は容易に検証制約の定義と実行が行えます。Bean ValidationはJava EE 7プラットフォームの一部として利用可能です。
この章では以下のトピックを扱います。
- Using Bean Validation Constraints
- Validating Null and Empty Strings
- Validating Constructors and Methods
- Further Information about Bean Validation
21.1 Using Bean Validation Constraints
Bean Validationモデルはアノテーション形式の制約によって実現されており、アノテーションはマネージドビーンなどのJavaBeansコンポーネントのクラス・メソッド・フィールドに付与します。
制約はビルトインもユーザ定義のどちらも使用可能です。ユーザ定義制約はカスタム制約と呼ばれます。たいてのビルトイン制約はjavax.validation.constraints
パッケージにあります。表 21-1にすべてのビルトイン制約を示します。カスタム制約の生成についてはCreating Custom Constraintsを参照してください。
表 21-1 ビルトインBean Validation制約の一覧
制約 | 説明 | 使用例 |
---|---|---|
@AssertFalse |
フィールドやプロパティの値がfalse である。 |
@AssertFalse boolean isUnsupported; |
@AssertTrue |
フィールドやプロパティの値がtrue である。 |
@AssertTrue boolean isActive; |
@DecimalMax |
フィールドやプロパティの値がアノテーションの要素値以下の10進数である。 | @DecimalMax("30.00") BigDecimal discount; |
@DecimalMin |
フィールドやプロパティの値がアノテーションの要素値以上の10進数である。 | @DecimalMin("5.00") BigDecimal discount; |
@Digits |
フィールドやプロパティの値が指定範囲内の数値である。integer 要素には最大の整数桁を指定し、fraction には最大の少数桁を指定します。 |
@Digits(integer=6, fraction=2) BigDecimal price; |
@Future |
フィールドやプロパティの値が未来の日時である。 | @Future Date eventDate; |
@Max |
フィールドやプロパティの値がアノテーションの要素値以下の整数である。 | @Max(10) int quantity; |
@Min |
フィールドやプロパティの値がアノテーションの要素値以上の整数である。 | @Min(5) int quantity; |
@NotNull |
フィールドやプロパティの値がnullではない。 | @NotNull String username; |
@Null |
フィールドやプロパティの値がnullである。 | @Null String unusedString; |
@Past |
フィールドやプロパティの値が過去である。 | @Past Date birthday; |
@Pattern |
フィールドやプロパティの値がregexp 要素の正規表現とマッチする。 |
@Pattern(regexp="\(\d{3}\)\d{3}-\d{4}") String phoneNumber; |
@Size |
評価されたフィールドやプロパティのサイズが指定範囲にマッチする。もしフィールドやプロパティがString の場合、文字列のサイズが評価されます。もしフィールドやプロパティがCollection の場合、Collection のサイズが評価されます。もしフィールドやプロパティがMap の場合、Map のサイズが評価されます。もしフィールドやプロパティが配列の場合、配列のサイズが評価されます。オプションのmax とmin 要素で範囲を指定します。 |
@Size(min=2, max=240) String briefMessage; |
以下のサンプルコードでは、ビルトインの@NotNull
制約をフィールドに付与しています。
public class Name { @NotNull private String firstname; @NotNull private String lastname; ... }
一つのJavaBeansコンポーネントオブジェクトに一つ以上の制約を付与することも可能です。たとえば、firstname
とlastname
フィールドにサイズの制約を付与できます。
public class Name { @NotNull @Size(min=1, max=16) private String firstname; @NotNull @Size(min=1, max=16) private String lastname; ... }
以下のサンプルは、企業の電子メールアカウントに対し、事前定義済みの電子メールパターンによるチェック制約をメソッドに付与しています。
@ValidEmail public String getEmailAddress() { return emailAddress; }
ビルトイン制約にはデフォルト実装が利用可能です。ユーザ定義やカスタム制約は検証ロジックの実装が必要です。前述の例では、@ValidEmail
カスタム制約が実装クラスを必要とします。
検証失敗時にはh:messages
タグで表示可能です。
Bean Validationを含むマネージドビーンは自動的にJSFアプリケーションのwebページのフィールドに配置される検証制約を取得します。
検証制約の詳細については下記を参照してください。
- Chapter 22, "Bean Validation: Advanced Topics"
- Validating Resource Data with Bean Validation
- Validating Persistent Fields and Properties
21.2 Validating Null and Empty Strings
プログラミング言語Javaはnullと空文字と区別します。空文字は長さゼロの文字列インスタンスで、null文字列は値を持ちません。
空文字は""として表現されます。ゼロ文字の文字シーケンスです。null文字列はnull
として表現されます。文字列インスタンスが無いことを意味します。
inputText
などのJSFテキストコンポーネントとして表現されるマネージドビーンの要素の初期値はJSF実装が空文字を割り当てます。そうしたフィールドにユーザ入力が不要である場合、文字列フィールドの検証には問題が生じます。以下のサンプルを考えてみると、testString
にユーザが入力した値が設定されて検証されるとします。このケースの場合、フィールドにユーザ入力は不要です。
if (testString==null) { doSomething(); } else { doAnotherThing(); }
デフォルトでは、ユーザが何も入力しなかったとしてもdoAnotherThing
が呼ばれます。その理由は、testString
要素は空文字で初期化されるためです。
意図通りにBean Validationを動作させるには、デプロイメント記述子web.xml
でコンテキストパラメータjavax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
をtrue
に設定します。
<context-param> <param-name> javax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL </param-name> <param-value>true</param-value> </context-param>
このパラメータはJSF実装が空文字をnullとして扱えるようにします。
一方、入力必須のために要素に@NotNul
を付与することを考えます。このケースの場合、空文字は検証制約を通過します。ただし、コンテキストパラメータjavax.faces.INTERPRET_EMPTY_STRING_SUBMITTED_VALUES_AS_NULL
をtrue
にする場合、マネージドビーンの値にはnullがBean Validationランタイムに渡され、@NotNull
制約は失敗します。
21.3 Validating Constructors and Methods
Bean Validation制約は非staticなメソッドとコンストラクタの引数や、非staticメソッドの戻り値に付与可能です。staticメソッドとコンストラクタは検証されません。
public class Employee { ... public Employee (@NotNull String name) { ... } public void setSalary( @NotNull @Digits(integer=6, fraction=2) BigDecimal salary, @NotNull @ValidCurrency String currencyType) { ... } ... }
この例では、Employee
クラスは氏名を必須とするコンストラクタ制約と、メソッド引数に二組の制約を持ちます。employeeのsalaryの制約は、nullではなく、整数6桁小数点以下2桁以内になります。currencyTypeの制約は、nullでなく、カスタム制約を使用しています。
オブジェクト階層のクラスにメソッド制約を付与する場合、サブタイプによる意図しない振る舞いを避けるために特別な配慮が必要です。 詳細についてはUsing Method Constraints in Type Hierarchiesを参照してください。
21.3.1 Cross-Parameter Constraints
クロスパラメータ制約(cross-parameter constraints)は複数のパラメータに適用される制約で、メソッドやコンストラクタレベルで適用可能です。
@ConsistentPhoneParameters @NotNull public Employee (String name, String officePhone, String mobilePhone) { ... }
この例では、カスタムのクロスパラメータ制約@ConsistentPhoneParameters
はコンストラクタの電話番号の形式が正しいかを検証します。@NotNull
制約はコンストラクタのすべての引数に適用されます。
Tip: クロスパラメータ制約はメソッドやコンストラクタに対して適用します。また、戻り値制約もメソッドやコンストラクタに対して適用します。制約を引数や戻り値に適用する場所に関する混乱を避けるために、カスタム制約が適用される場所を一意に識別できるアノテーション名にしてください。たとえば、先述のカスタム制約@ConsistentPhoneParameters
はメソッドやコンストラクタの引数に適用されることを示しています。
メソッドの引数と戻り値両方に適用されるカスタム制約を作成する場合、検証制約のターゲットを明示的に設定するために、制約アノテーションのvalidationAppliesTo
要素にConstraintTarget.RETURN_VALUE
やConstraintTarget.PARAMETERS
を設定します。
21.3.2 Identifying Parameter Constraint Violations
メソッド呼び出し時にConstraintViolationException
が発生する場合、Bean Validationランタイム制約違反のあった引数インデックスを返します。引数インデックスの形式はargPARAMETER_INDEX
で、PARAMETER_INDEXはメソッドやコンストラクタの最初の引数がゼロから始まる整数です。
21.3.3 Adding Constraints to Method Return Values
メソッドの戻り値を検証するには、メソッドやコンストラクタ宣言に制約を付与します。
@NotNull public Employee getEmployee() { ... }
クロスパラメータ制約はメソッドレベルにも適用可能です。戻り値とメソッド引数両方に適用が可能なカスタム制約のターゲットは曖昧になります。曖昧さを避けるには、制約アノテーション定義のターゲットを明示的に設定するために、validationAppliesTo
要素にConstraintTarget.RETURN_VALUE
かConstraintTarget.PARAMETERS
のどちらかをデフォルト設定します。
@Manager(validationAppliesTo=ConstraintTarget.RETURN_VALUE) public Employee getManager(Employee employee) { ... }
詳細についてはRemoving Ambiguity in Constraint Targetsを参照してください。
21.4 Further Information about Bean Validation
Bean Validationのより詳しい情報については下記を参照してください。
- Bean Validation 1.1 Specification:
http://www.jcp.org/en/jsr/detail?id=349 - Bean Validation Specification website:
http://beanvalidation.org/
関連リンク
- The Java EE 7 Tutorialのテキトー翻訳まとめ - Qiita - Java EE 7 Tutorialのうち、自分がテキトー翻訳したものの一覧