Validator.validateValue 忽略了在 beanType 为接口时的验证(hibernate-validator-6.0.18)

huangapple go评论81阅读模式
英文:

Validator.validateValue ignores validation when beanType is an interface (hibernate-validator-6.0.18)

问题

我已经创建了一个只包含用于建模领域对象的接口的库。这些接口具有(类、属性、方法和构造函数级别的)约束,我想要进行测试。

例如:

public interface User {
    @NotNull
    @Email
    String getEmail();
}

我想要测试这些约束是否被正确应用,因此我编写了一些测试。然而,我得到了意外的行为。

class UserTest {
    @Test
    void thisTestFails() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<User>> violations = validator.validateValue(User.class, "email", null);
        assertEquals(1, violations.size());
    }

    @Test
    void thisTestPasses() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set<ConstraintViolation<UserImpl>> violations = validator.validateValue(UserImpl.class, "email", null);
        assertEquals(1, violations.size());
    }

    private static class UserImpl implements User {
        @Override
        public String getEmail() {
            return null;
        }
    }
} 

当提供给 Class<T> beanType 的参数为接口时,Hibernate 完全忽略了验证。我不想为了测试这些接口而创建具体类。这是预期的行为还是 Hibernate 中的一个错误?

英文:

I have created a library that contains only Interfaces that model domain objects. These interfaces have (class, property, method, and constructor level) constraints I want to test.

For example:

public interface User {
    @NotNull
    @Email
    String getEmail();
}

I want to test the constraints are getting applied correctly, so I have written some tests. However, I get unexpected behavior.

class UserTest {
    @Test
    void thisTestFails() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set&lt;ConstraintViolation&lt;User&gt;&gt; violations = validator.validateValue(User.class, &quot;email&quot;, null);
        assertEquals(1, violations.size());
    }

    @Test
    void thisTestPasses() {
        Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
        Set&lt;ConstraintViolation&lt;UserImpl&gt;&gt; violations = validator.validateValue(UserImpl.class, &quot;email&quot;, null);
        assertEquals(1, violations.size());
    }

    private static class UserImpl implements User {
        @Override
        public String getEmail() {
            return null;
        }
    }
} 

Hibernate completely ignores validation when the argument provided for Class&lt;T&gt; beanType is an interface.
I do not want to create concrete classes just to test these interfaces. Is this the expected behavior or a bug in Hibernate?

答案1

得分: 1

以下是翻译好的内容:

这是预期的行为。Bean Validation 规范定义了约束可以在接口或类中定义,但要验证的是遵循 Java Beans 约定的属性状态。

一个接口可以定义一个由类实现的 getter 方法,但它本身并没有这个属性。

以下是规范中的相关部分:

> 5.1.1. 对象验证
>
> 约束声明可以应用于类或接口。将约束应用于类或接口表示对类的状态或实现接口的类进行验证。
>
> 5.1.2. 字段和属性验证
>
> 约束声明可以同时应用于同一对象类型的字段和属性。然而,不应在字段和其关联属性之间重复使用相同的约束(约束验证将被应用两次)。建议包含约束声明的对象遵循单一状态访问策略(可以是带注解的字段或属性)。
>
> 当字段带有约束声明的注解时,使用字段访问策略来访问此约束验证的状态。
>
> 当属性带有约束声明的注解时,使用属性访问策略来访问此约束验证的状态。

确实,validateValue 方法不需要实例,因此从理论上讲,它可以测试接口的约束。但请注意,类参数是一个 beanType,而 bean 的类型必须是一个类,因为接口没有构造函数。

请注意,与 Validator 中的 getConstraintsForClass 方法相比,该方法明确说明可以获取在接口上声明的约束:

> 评估的类或接口类型

validateValue 的类参数:

> bean 类型

英文:

This is the expected behavior. The Bean Validation spec defines that constraints can be defined in interfaces or classes, but what is validated is the state of property that follows the Java Beans conventions.

An interface can define a getter method that is implemented by a class, but it hasn't the property itself.

That are the relevant parts of the specification:

> 5.1.1. Object validation
>
> Constraint declarations can be applied to a class or an interface. Applying a constraint to a class or interface
> expresses a validation over the state of the class or the class
> implementing the interface
.
>
> 5.1.2. Field and property validation
>
> Constraint declarations can be applied on both fields and properties
> for the same object type. The same constraint should however not be
> duplicated between a field and its associated property (the constraint
> validation would be applied twice). It is recommended for objects
> holding constraint declarations to adhere to a single state access
> strategy (either annotated fields or properties).
>
> When a field is annotated with a constraint declaration, field access
> strategy is used to access the state validated by such constraint.
>
> When a property is annotated with a constraint declaration, property
> access strategy is used to access the state validated by such
> constraint
.

It's true that the validateValue method doesn't require an instance, so theoretically it could test the constraints of an interface. But note that the class parameter, it's a beanType, and the type of a bean needs to be a class, as an interface has no constructors.

Note the difference with the method getConstraintsForClass also from Validator that explicitly states that can get the constrains declared on an interfaces:

> class or interface type evaluated

While the class parameter of validateValue:

> the bean type

huangapple
  • 本文由 发表于 2020年3月4日 03:54:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/60514567.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定