2つ以上のフィールドを組み合わせて検証するにはどうすればいいですか? 質問する

2つ以上のフィールドを組み合わせて検証するにはどうすればいいですか? 質問する

私はモデルを検証するために JPA 2.0/Hibernate 検証を使用しています。現在、2 つのフィールドの組み合わせを検証する必要がある状況があります。

public class MyModel {
    public Integer getValue1() {
        //...
    }
    public String getValue2() {
        //...
    }
}

モデルは無効getValue1()と の両方が正しい場合は有効getValue2()でありnull、それ以外の場合は有効です。

JPA 2.0/Hibernate でこのような検証を実行するにはどうすればよいでしょうか? 単純な@NotNullアノテーションでは、検証に合格するには両方のゲッターが null 以外である必要があります。

ベストアンサー1

複数のプロパティの検証には、クラスレベルの制約を使用する必要があります。Bean Validation のプレビュー パート II: カスタム制約:

クラスレベルの制約

複数のプロパティにまたがる制約を適用する機能や、複数のプロパティに依存する制約を表現する機能について懸念を表明する方もいらっしゃいます。典型的な例は住所の検証です。住所には複雑なルールがあります。

  • 通りの名前はある程度標準化されており、長さの制限が必ずあるはずです。
  • 郵便番号の構造は国によって完全に異なります
  • 都市は多くの場合郵便番号と相関関係があり、エラーチェックも実行できます(検証サービスにアクセスできる場合)。
  • これらの相互依存性のため、単純なプロパティレベルの制約では不十分である。

Bean Validation 仕様が提供するソリューションは 2 つあります。

  • グループとグループシーケンスを使用して、ある制約セットを他の制約セットの前に強制的に適用する機能を提供します。このテーマについては、次のブログエントリで説明します。
  • クラスレベルの制約を定義できる

クラス レベルの制約は、プロパティではなくクラスに適用される通常の制約 (注釈と実装のデュオ) です。言い換えると、クラス レベルの制約は、プロパティ値ではなくオブジェクト インスタンスを受け取りますisValid

@AddressAnnotation 
public class Address {
    @NotNull @Max(50) private String street1;
    @Max(50) private String street2;
    @Max(10) @NotNull private String zipCode;
    @Max(20) @NotNull String city;
    @NotNull private Country country;
    
    ...
}

@Constraint(validatedBy = MultiCountryAddressValidator.class)
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface AddressAnnotation {
    String message() default "{error.address}";
    Class<?>[] groups() default { };
    Class<? extends Payload>[] payload() default { };
}

public class MultiCountryAddressValidator implements ConstraintValidator<AddressAnnotation, Address> {
    public void initialize(AddressAnnotation constraintAnnotation) {
    // initialize the zipcode/city/country correlation service
    }

    /**
     * Validate zipcode and city depending on the country
     */
    public boolean isValid(Address object, ConstraintValidatorContext context) {
        if (!(object instanceof Address)) {
            throw new IllegalArgumentException("@AddressAnnotation only applies to Address objects");
        }
        Address address = (Address) object;
        Country country = address.getCountry();
        if (country.getISO2() == "FR") {
            // check address.getZipCode() structure for France (5 numbers)
            // check zipcode and city correlation (calling an external service?)
            return isValid;
        } else if (country.getISO2() == "GR") {
            // check address.getZipCode() structure for Greece
            // no zipcode / city correlation available at the moment
            return isValid;
        }
        // ...
    }
}

高度なアドレス検証ルールは、アドレス オブジェクトから除外され、 によって実装されていますMultiCountryAddressValidator。オブジェクト インスタンスにアクセスすることで、クラス レベルの制約は柔軟性が高くなり、複数の相関プロパティを検証できます。順序はここでは考慮されていないことに注意してください。これについては、次の投稿で説明します。

専門家グループは、さまざまな複数プロパティのサポート アプローチについて議論しました。クラス レベルの制約アプローチは、依存関係を伴う他のプロパティ レベルのアプローチと比較して、十分なシンプルさと柔軟性の両方を提供すると考えています。フィードバックをお待ちしています。

おすすめ記事