Bean Validation 2.0を使ったコンテナ要素の検証
1概要
2.0バージョンの
Java Bean Validation
仕様には、いくつかの新機能が追加されています。その中には、コンテナの要素を検証する機能もあります。
この新しい機能は、Java 8で導入された型注釈を利用します。したがって、機能するにはJavaバージョン8以降が必要です。
-
バリデーションアノテーションは、コレクション、
Optional
オブジェクト、その他の組み込みおよびカスタムコンテナなどのコンテナに追加できます。
Java Beanの検証
の概要と必要な
Maven
の依存関係の設定方法については、リンク:/javax-validation[前の記事]を参照してください。
次のセクションでは、各種類のコンテナの要素の検証に焦点を当てます。
2コレクション要素
java.util.Iterable
、
java.util.List
、および
java.util.Map
型のコレクションの要素に検証アノテーションを追加できます。
リストの要素を検証する例を見てみましょう。
public class Customer {
List<@NotBlank(message="Address must not be blank") String> addresses;
//standard getters, setters
}
上記の例では、
Customer
クラスの
addresses
プロパティを定義しました。このクラスには、空にできない要素
Strings
が含まれています。
-
@ NotBlank
検証は
String
要素に適用され、コレクション全体には適用されません** 。コレクションが空の場合、検証は適用されません。
空の
String
を
addresses
リストに追加しようとすると、検証フレームワークが
ConstraintViolation
を返すことを確認しましょう。
@Test
public void whenEmptyAddress__thenValidationFails() {
Customer customer = new Customer();
customer.setName("John");
customer.setAddresses(Collections.singletonList(" "));
Set<ConstraintViolation<Customer>> violations =
validator.validate(customer);
assertEquals(1, violations.size());
assertEquals("Address must not be blank",
violations.iterator().next().getMessage());
}
次に、
Map
型のコレクションの要素を検証する方法を見てみましょう。
public class CustomerMap {
private Map<@Email String, @NotNull Customer> customers;
//standard getters, setters
}
Map
要素のキーと値の両方に検証アノテーションを追加できることに注意してください。
無効な電子メールを含むエントリを追加すると検証エラーが発生することを確認しましょう。
@Test
public void whenInvalidEmail__thenValidationFails() {
CustomerMap map = new CustomerMap();
map.setCustomers(Collections.singletonMap("john", new Customer()));
Set<ConstraintViolation<CustomerMap>> violations
= validator.validate(map);
assertEquals(1, violations.size());
assertEquals(
"Must be a valid email",
violations.iterator().next().getMessage());
}
3 __オプションの値
検証制約は、
Optional
値にも適用できます。
private Integer age;
public Optional<@Min(18) Integer> getAge() {
return Optional.ofNullable(age);
}
年齢が低すぎる
Customer
を作成し、検証エラーになることを確認します。
@Test
public void whenAgeTooLow__thenValidationFails() {
Customer customer = new Customer();
customer.setName("John");
customer.setAge(15);
Set<ConstraintViolation<Customer>> violations
= validator.validate(customer);
assertEquals(1, violations.size());
}
一方、
age
がnullの場合、
Optional
値は検証されません。
@Test
public void whenAgeNull__thenValidationSucceeds() {
Customer customer = new Customer();
customer.setName("John");
Set<ConstraintViolation<Customer>> violations
= validator.validate(customer);
assertEquals(0, violations.size());
}
4非汎用コンテナ要素
型引数に注釈を追加する以外に、
@ UnwrapByDefault
注釈を持つ型の値抽出プログラムがある限り、非汎用コンテナに検証を適用することもできます。
値抽出プログラムは、検証のためにコンテナから値を抽出するクラスです。
-
リファレンス実装には、
OptionalInt
、
OptionalLong
、および
OptionalDouble
** の値エクストラクタが含まれています。
@Min(1)
private OptionalInt numberOfOrders;
この場合、
@ Min
アノテーションはラップされた
Integer
値に適用され、コンテナーには適用されません。
5カスタムコンテナエレメント
組み込みの値エクストラクタに加えて、独自のものを定義し、それらをコンテナ型で登録することもできます。
このようにして、カスタムコンテナの要素に検証アノテーションを追加することができます。
companyName
プロパティを含む新しい
Profile
クラスを追加しましょう。
public class Profile {
private String companyName;
//standard getters, setters
}
次に、
Customer
クラスに
@ NotBlank
アノテーションを使用して
Profile
プロパティを追加します。これにより、
companyName
が空の
String
ではないことを確認します。
@NotBlank
private Profile profile;
これが機能するには、プロファイルオブジェクトではなく
companyName
プロパティに適用される検証を決定する値抽出プログラムが必要です。
ValueExtractor
インターフェイスを実装し、
extractValue()メソッドをオーバーライドする
ProfileValueExtractor__クラスを追加しましょう。
@UnwrapByDefault
public class ProfileValueExtractor
implements ValueExtractor<@ExtractedValue(type = String.class) Profile> {
@Override
public void extractValues(Profile originalValue,
ValueExtractor.ValueReceiver receiver) {
receiver.value(null, originalValue.getCompanyName());
}
}
このクラスは、
@ ExtractedValue
アノテーションを使用して抽出された値の型も指定する必要があります。
また、検証をコンテナではなくラップされていない値に適用するように指定する
@ UnwrapByDefault
アノテーションを追加しました** 。
最後に、
javax.validation.valueextraction.ValueExtractor
というファイルを
ProfileValueExtractor
クラスのフルネームを含む
META-INF/services
ディレクトリに追加して、クラスを登録する必要があります。
org.baeldung.valueextractors.ProfileValueExtractor
空の
companyName
を持つ
profile
プロパティで
Customer
オブジェクトを検証すると、検証エラーが発生します。
@Test
public void whenProfileCompanyNameBlank__thenValidationFails() {
Customer customer = new Customer();
customer.setName("John");
Profile profile = new Profile();
profile.setCompanyName(" ");
customer.setProfile(profile);
Set<ConstraintViolation<Customer>> violations
= validator.validate(customer);
assertEquals(1, violations.size());
}
hibernate-validator-annotation-processor
を使用している場合、カスタムコンテナクラスに検証アノテーションを追加すると、
@ UnwrapByDefault
とマークされていると、バージョン6.0.2でコンパイルエラーになります。
これはhttp://docs.jboss.org/hibernate/stable/validator/reference/en-US/html__single/#validator-annotationprocessor-known-issues[既知の問題]であり、将来のバージョンで解決される可能性があります。
6. 結論
この記事では、__Java Bean Validation 2.0を使っていくつかのタイプのコンテナ要素を検証する方法を説明しました。
over on GitHub
の例の完全なソースコードを見つけることができます。