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

时间:2010-05-06 14:21:36

标签: java jpa jpa-2.0 bean-validation

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

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

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

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

4 个答案:

答案 0 :(得分:74)

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

  

类级约束

     

有些人表达了担忧   关于申请的能力   约束跨越多个   属性,或表达约束   这取决于几个属性。   经典的例子是地址   验证。地址错综复杂   规则:

     
      
  • 街道名称有些标准,必须有长度限制
  •   
  • 邮政编码结构完全取决于国家/地区
  •   
  • 城市通常可以与邮政编码相关联,并且可以进行一些错误检查   完成(如果验证   服务是可以访问的)
  •   
  • 因为这些相互依赖性,一个简单的属性级别约束就是这样   适合该法案
  •   
     

Bean提供的解决方案   验证规范是双重的:

     
      
  • 它提供了强制在一个约束之前应用一组约束的能力   通过其他一组约束   使用组和组序列。   该主题将在本课程中介绍   下一篇博客文章
  •   
  • 它允许定义类级约束
  •   
     

类级别约束是常规的   约束(注释/   实施二人组)适用于   阶级而不是财产。说过   不同的是,类级约束   接收对象实例(相反   比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("@Address only applies to Address");
        }
        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。通过   访问对象实例,类   等级约束有很多   灵活性,可以验证多个   相关属性。注意   排序不在等式中   在这里,我们将回到它   下一篇文章。

     

专家组讨论了各种问题   多个属性支持   方法:我们认为班级   约束方法提供了两者   足够简单和灵活   与其他财产水平相比   涉及依赖的方法。   欢迎您的反馈。

答案 1 :(得分:24)

要与Bean Validation一起正常使用,Pascal Thivent的answer中提供的示例可以重写如下:

select
    projects.name, 
    sum(current_date - (projects_programmers.joined_at))
    from projects, projects_programmers
where projects.id = projects_programmers.project_id
group by projects.name, projects_programmers.joined_at
@ValidAddress
public class Address {

    @NotNull
    @Size(max = 50)
    private String street1;

    @Size(max = 50)
    private String street2;

    @NotNull
    @Size(max = 10)
    private String zipCode;

    @NotNull
    @Size(max = 20)
    private String city;

    @Valid
    @NotNull
    private Country country;

    // Getters and setters
}
public class Country {

    @NotNull
    @Size(min = 2, max = 2)
    private String iso2;

    // Getters and setters
}
@Documented
@Target(TYPE)
@Retention(RUNTIME)
@Constraint(validatedBy = { MultiCountryAddressValidator.class })
public @interface ValidAddress {

    String message() default "{com.example.validation.ValidAddress.message}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};
}

答案 2 :(得分:8)

当您希望继续使用Bean Validation规范时,可以使用类级别验证器。如果您乐意使用Hibernate Validator功能,可以使用Validator-4.1.0.Final中提供的 @ScriptAssert

答案 3 :(得分:0)

编程语言:Java

这是一个对我有帮助的解决方案。

要求:

  1. 在 UI 上有一个包含对象列表的表格,该列表具有映射到具有 fk 关系的多个表格/对象。

  2. 现在验证是在多个 fks 之外,只有 3 列无法复制。我的意思是 3 的组合不能重复。

注意:当我在 Java 上开发自定义框架时,没有使用 HashCode 或 equals 的选项。如果我将使用数组索引迭代,这将增加我不想要的时间复杂度。

解决方案:

我准备了一个 String ,它是一个自定义的 String ,包含 FK1#ID of FK2#ID of FK3 例如:字符串的形式如下 -> 1000L#3000L#1300L#

这个字符串,我们将使用 set 的 add() 添加到一个集合中,如果出现重复,它将返回 false。

基于这个标志,我们可以抛出验证消息。

这对我有帮助。 DS 可能无济于事。