Bean Validation
Bean Validation API は、アプリケーションのすべての層 (プレゼンテーション、ビジネス、およびデータ・アクセスなど) で JavaBeans を検証する標準メカニズムとして Java™ Enterprise Edition 6 プラットフォームで導入されました。
Bean Validation の仕様が規定される前には、各層で JavaBeans の検証が行われていました。 各層での検証の再実装を避けるため、開発者は、検証をクラスに直接組み込んだり、 検証のコードをコピーしたりしていました。そのため、多くの場合、コードは乱雑になりがちでした。アプリケーションのすべての層に共通する 1 つの実装にまとめることは、 開発者の作業の合理化と時間の節約になります。
Bean Validation 仕様では、JavaBeans のデータ整合性を検証するために使用されるメタデータ・モデルと API が定義されます。メタデータ・モデルは、XML 検証記述子を使用して指定変更および拡張可能な定義済みの制約アノテーションです。 API のセットにより、使いやすいプログラミング・モデルが提供され、どのアプリケーション層でも一連の同じ検証制約を使用できます。 検証制約は、アノテーションが付けられたフィールド、メソッド、およびタイプの値を検査して、それらが定義済みの制約に従っているかどうか確認するために使用されます。
制約には、組み込み制約とユーザー定義制約があります。 いくつかの組み込みアノテーションが javax.validation.constraints パッケージに入っています。これらは、通常の制約定義を定義するため、および制約を構成するために使用されます。 組み込み制約のリストについては、Bean Validation の組み込み制約の資料を参照してください。Bean Validation メタデータ・モデルおよび API について詳しくは、JSR 349 Bean Validation の仕様書を参照してください。
組み込みの制約のアノテーションによって修飾された単純な Enterprise JavaBeans (EJB) クラスの例を次に示します。
public class Home {
@Size(Max=20)
String builder;
@NotNull @Size(Max=20)
String address;
public String getAddress() {
return address;
}
public String getBuilder() {
return address;
}
public String setAddress(String newAddress) {
return address = newAddress;
}
public String setBuilder(String newBuilder) {
return builder = newBuilder;
}
}
builder および address に対する @Size アノテーションにより、割り当てられるストリング値が 20 文字を超えてはならないことが指定されています。 address に対する @NotNull アノテーションでは、この値をヌルにできないことが示されています。 Home オブジェクトの検証が実行される際、@Size アノテーションに対して定義されたバリデーター・クラスに builder および address の値が渡されます。 address の値は、@NotNull のバリデーター・クラスにも渡されます。 バリデーター・クラスは、いくつかの適切な制約に対して値の検査を実行します。何らかの制約について検証が不合格だった場合は、ConstraintViolation オブジェクトが作成され、この Home オブジェクトの検証を実行した呼び出し元に対してセットで返されます。
Validation API
javax.validation パッケージには、JavaBeans をプログラムで検証する方法を記述する Bean Validation API が含まれています。
ConstraintViolation は、単一の制約違反を記述したクラスです。 1 度のオブジェクト検証に対して一連の ConstraintViolation クラスが返されます。 制約違反では、違反についての人間が理解可能な説明メッセージも公開されます。
検証中に違反が見つかると、ValidationException が発生します。
Validator インターフェースは、メインの Validation API であり、Validator インスタンスは、Java オブジェクト・フィールド、メソッド、および型の値を妥当性検査できるオブジェクトです。ブートストラッピング API は、Validator インスタンスを作成するために使用される ValidatorFactory にアクセスするためのメカニズムです。 製品にデプロイされたアプリケーションの場合、ブートストラッピングは自動的に実行されます。 アプリケーションがバリデーターまたは ValidatorFactory を取得するには、2 つの方法があります。1 つ目は注入で (@Resource アノテーションなどを使用)、もう 1 つは Java の lookup です。
@Resource ValidatorFactory _validatorFactory;
@Resource Validator _validator;
ValidatorFactory validatorFactory = (ValidatorFactory)context.lookup("java:comp/ValidatorFactory");
Validator validator = (Validator)context.lookup("java:comp/Validator");
制約メタデータ要求 API
メタデータ API は、ツール・プロバイダーをサポートし、他のフレームワーク、ライブラリー、および Java Platform, Enterprise Edition テクノロジーとの統合を実現します。オブジェクト制約のメタデータ・リポジトリーには、所定のクラスの Validator インスタンスからアクセスします。
XML デプロイメント記述子
アノテーションでの制約の宣言のほか、XML を使用した制約の宣言もサポートされています。
検証の XML 記述は、2 種類の xml ファイルから構成されます。 META-INF/validation.xml ファイルには、モジュールの Bean Validation 構成が記述されます。 もう一方の XML ファイル・タイプには、制約の宣言を記述します。これはアノテーション宣言方式とよく似ています。 デフォルト時、XML に記述されたクラスでは、アノテーションによって表されたすべての制約宣言が無視されます。 Bean で ignore-annotation="false" 設定を使用することにより、検証でアノテーションと XML 制約宣言の両方を強制的に使用することができます。 本製品では、XML 記述子を含むモジュールに固有のバリデーター・インスタンスを作成することによって、validation.xml ファイル、および XML ファイルに定義された制約を含むデプロイ済みアプリケーション・モジュールを、他のモジュールの validation.xml ファイルおよび制約ファイルから分離します。
Bean Validation の上級概念
Bean Validation API には、一連の組み込み制約、およびカスタム制約の宣言を可能にするインターフェースが用意されています。 これは、制約アノテーションを作成し、Bean のタイプ、フィールド、またはプロパティーへのアノテーションを宣言することによって行われます。 制約の構成は、別の制約定義で制約を宣言することによっても行われます。
以下に示すのは、コメント・ストリング・フィールドが非ヌルであることを確認するために定義される CommentChecker 制約を作成する場合の例です。 コメント・テキストは、大括弧で囲まれます ([text] など)。
package com.my.company;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import javax.validation.Constraint;
import javax.validation.Payload;
@Documented
@Constraint(validatedBy = CommentValidator.class)
@Target({ METHOD, FIELD })
@Retention(RUNTIME)
public @interface CommentChecker {
String message() default "The comment is not valid.";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
…}
package com.my.company;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
public class CommentValidator implements ConstraintValidator<CommentChecker, String> {
public void initialize(CommentChecker arg0) {
}
public boolean isValid(String comment, ConstraintValidatorContext context) {
if (comment == null) {
// Null comment is not allowed, fail the constraint.
return false;
}
if (!comment.contains("[") && !comment.contains("]")) {
// Can't find any open or close brackets, fail the constraint
return false;
}
// Ignore leading and trailing spaces
String trimmedComment = comment.trim();
return // validate '[' prefix condition
trimmedComment.charAt(0) == '[' &&
// validate ']' suffix condition
trimmedComment.charAt(trimmedComment.length()!-1) == ']';
}
}
@CommentChecker を定義した後は、それを使用して、コメント・ストリング・フィールドが有効なコメントであるかどうかを CommentValidator isValid() 実装に基づいて確認することができます。
以下に示すのは、@CommentChecker 制約の使用例です。
myChecker Bean の検証が実行される際、CommentValidator クラスによってコメント・ストリングの検証が行われ、定義済みの制約が満たされているかどうかが確認されます。
package com.my.company;
public myChecker {
@CommentChecker
String comment = null;
...
}
本製品にはデフォルトの Bean Validation プロバイダーが用意されていますが、アプリケーションで代替のプロバイダーを使用したい場合もあります。javax.validation.Validation.byProvider() メソッドを呼び出して検証ファクトリーを作成することにより、プログラムで代替のプロバイダーを選択することができます。あるいは、validation.xml ファイルに <default-provider/> エレメントを指定することで、宣言として代替プロバイダーを選択することもできます。代替のプロバイダー・クラスがデフォルトのプロバイダーと競合しないようにするには、サーバーまたはアプリケーションのクラス・ローダー順序を、最初にローカル・クラス・ローダーでロードしたクラス (親が最後) の値に設定する必要があります。 この設定値の設定方法についての追加情報は、クラス・ロードに関する文書を参照してください。
Bean Validation 仕様では、クラスパスに複数の validation.xml ファイルがある場合、ValidationException が発生することが示されています。 ただし、WebSphere® Application Server は、複数のチームが Application Server に一緒にアセンブルおよびデプロイされるモジュールを開発する環境をサポートしています。この環境では、アプリケーション内のすべての EJB モジュールが同じクラス・ローダーを使用してロードされます。また、すべての EJB モジュールおよび Web アーカイブ (WAR) モジュールが単一のクラス・ローダーによってロードされるようにアプリケーション・クラス・ローダーを構成することができます。 そのため、本製品では、同じクラスパス内にある複数の validation.xml ファイルをサポートしています。
<constraint-mapping>META-INF/constraints-house.xml</constaint-mapping>
<constraint-mapping>META-INF/constraints-rooms.xml</constraint-mapping>
この動作の例外は、すべての Bean Validation 制約クラスおよび構成が、すべてのアプリケーション・モジュールから可視の場合です。 EAR ファイルに単一の validation.xml ファイルが定義されていて、モジュールのクラスパスで他の validation.xml ファイルが可視になっていない場合は、バリデーター・ファクトリーまたはバリデーターを作成するモジュールはすべて、EAR ファイルに定義されている validation.xml ファイルを使用します。このことによって、他のモジュールが別のモジュールの validation.xml ファイルを使用するバリデーター・ファクトリーを作成できるようになります (両方のモジュールが同じクラスパス上で可視になり、それらのモジュールに対して validation.xml ファイルが 1 つだけ可視になるように、クラスパスが構成されている場合)。
Bean Validation API およびメタデータについて詳しくは、JSR 349 Bean Validation 仕様書を参照してください。