java - 如何组合验证两个或多个字段?

标签 java jpa jpa-2.0 bean-validation

我正在使用 JPA 2.0/Hibernate 验证来验证我的模型。我现在有一种情况,必须验证两个字段的组合:

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

如果 getValue1()getValue2() 都是 null,则模型为 invalid,否则有效。

如何使用 JPA 2.0/Hibernate 执行这种验证?使用简单的 @NotNull 注释,两个 getter 都必须为非 null 才能通过验证。

最佳答案

对于多个属性验证,您应该使用类级别的约束。从 Bean Validation Sneak Peek part II: custom constraints :

Class-level constraints

Some of you have expressed concerns about the ability to apply a constraint spanning multiple properties, or to express constraint which depend on several properties. The classical example is address validation. Addresses have intricate rules:

  • a street name is somewhat standard and must certainly have a length limit
  • the zip code structure entirely depends on the country
  • the city can often be correlated to a zipcode and some error checking can be done (provided that a validation service is accessible)
  • because of these interdependencies a simple property level constraint does to fit the bill

The solution offered by the Bean Validation specification is two-fold:

  • it offers the ability to force a set of constraints to be applied before an other set of constraints through the use of groups and group sequences. This subject will be covered in the next blog entry
  • it allows to define class level constraints

Class level constraints are regular constraints (annotation / implementation duo) which apply on a class rather than a property. Said differently, class-level constraints receive the object instance (rather than the property value) in 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;
        }
        // ...
    }
}

The advanced address validation rules have been left out of the address object and implemented by MultiCountryAddressValidator. By accessing the object instance, class level constraints have a lot of flexibility and can validate multiple correlated properties. Note that ordering is left out of the equation here, we will come back to it in the next post.

The expert group has discussed various multiple properties support approaches: we think the class level constraint approach provides both enough simplicity and flexibility compared to other property level approaches involving dependencies. Your feedback is welcome.

关于java - 如何组合验证两个或多个字段?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2781771/

相关文章:

java - 在 JDBC 类中捕获 UnknownHostException

java - 多对多 jpa stackoverflow

java - 唯一约束异常后保存实体

hibernate - 实体管理器返回 @OneToMany 相关实体的重复副本

java - 获取调用者方法 (java.lang.reflect.Method)

java - 仅使用测试库创建测试目录

java - AspectJ 可以与 Java 7 一起使用吗?

jpa - Eclipselink 2.6.0 查询的目的 - SELECT ID FROM TBL WHERE ID=?

java - 生成 JPA 动态类型化查询的最佳实践?

java - 父ID未保存在子表Spring JPA2 @OneToMany关系中