JSR 303 Bean 验证 - 为啥使用 getter 而不是 setter?

Posted

技术标签:

【中文标题】JSR 303 Bean 验证 - 为啥使用 getter 而不是 setter?【英文标题】:JSR 303 Bean Validation - Why on getter and not setter?JSR 303 Bean 验证 - 为什么使用 getter 而不是 setter? 【发布时间】:2011-09-11 03:23:30 【问题描述】:

我不明白为什么 JSR 303(bean 验证)适用于 getter 方法而不适用于 setter?将它放在 setter 方法下不是更合乎逻辑吗,因为这是一个字段的入口点,并且应该在此之前检查验证?

【问题讨论】:

我不明白您为什么要将约束放在吸气剂而不是字段本身上。将它放在字段本身上不是更合乎逻辑吗,因为那是唯一的字段本身? @BalusC 是的!我同意你的看法。所以问题是如果我对那个字段进行验证,我是否还需要在那个字段 getter 方法上添加注释?如果没有,为什么getter方法根本没有注释? 你绝对不应该把它放在两个地方。根据 Hibernate 文档,它将导致该字段被验证两次。 同样的问题,放在 setter 或 field 本身更直观。一些库在错误的地方使用它,现在由于验证异常我无法加载这些库 【参考方案1】:

这是一个非常好的问题,而且我从未关注过。但我想我知道答案(以及为什么我自己从来没有收到过这个问题)。

如果你正在看这个,从这个角度来看,注释定义了验证将发生的位置,那么将它放在 getter 上是没有意义的。 (为什么在存储值本身时不进行验证..)。但这不是它的工作原理......

程序员需要告诉验证框架,哪些属性需要验证。因此,您可以将注释直接放在属性上(我更喜欢),也可以将其放在 getter 上。它们都表示读操作。框架需要读取您的类的所有属性,这些属性必须经过验证。所以在这种情况下,装上setter一点意义都没有。理解的关键是视角……

我希望这是有道理的。

【讨论】:

是的,如果你这样看它是没有意义的。我不认为将您的注释定位在 getter 上,而是在 getter 上执行验证。我们只是将该属性标记为框架需要验证的内容。 我明白你想说什么。据我了解 JSF 生命周期,如果在流程验证阶段出现验证错误,则会重新显示相同的页面。不应该调用 setter 方法来进行验证吗?仅在页面呈现阶段调用 getter 方法。为什么要在页面渲染阶段进行验证?在我看来,在这个阶段进行验证是没有意义的,因为......现在一切都很好,因此所述页面被渲染以供显示。 这是因为有些情况下没有setter方法。设置器不会包含在只读属性中。【参考方案2】:

注释 getter 并不意味着在调用 getter 时执行验证。它仅用于标识应应用约束的属性。

将约束放在(通常是公共的)getter 上而不是放在(通常是私有的)字段上的最大优势在于,约束是该类型公共 API 的一部分。它们甚至会被添加到生成的 JavaDoc 中。一个类型的用户知道哪些约束适用于它,而无需查看其内部实现。

注释 getter 的另一个优点是可以将约束放在基类或接口的方法上,也可以应用于任何子类型/实现。

【讨论】:

如果是这种情况,如果对公共 setter 方法施加约束,我看不到任何问题。与您的答案相同的结果 我认为使用 getter 而不是 setter 方法的一个优点是,这允许拥有不存在 setter 的不可变属性,同时获得属性级别(相对于字段级别)约束的优势,如上所述。 @yapkm01 请看我的回答。 setter 方法有问题。您不能总是使用公共 setter 方法预测正确的字段。【参考方案3】:

考虑这段代码:

public class BeanValidation 

    private int nameSetCount = 0;
    private int nameGetCount = 0;
    private String name;

    public String getName() 
        this.nameGetCount++;
        return name;
    

    public void setName(String name) 
        this.nameSetCount++;
        this.name = name;
    


private String name;上添加注释

只需查看字段,注释即可轻松识别字段。

public String getName()上添加注释

只需查看返回的字段,注释即可轻松识别字段。

public void setName(String name)上添加注释

注解无法识别字段查看修改后的字段,因为可能有多个。

【讨论】:

反射不查看方法实现,它查看 getter/setter 的名称并将其与字段匹配【参考方案4】:

Bean Validation 以这种方式调用是有原因的。它应用于一个初始化的bean。所以,首先,你用你所有的东西初始化它,然后你把它(或者它被显式地传递)传递给 Bean Validation 实现,它在访问字段时将依赖于验证注解。 如果 Spring MVC 验证处理开始于:

result = execVal.validateParameters(
                invocation.getThis(), methodToValidate, invocation.getArguments(), groups);

MethodValidationInterceptor 内。从这里开始,它被传递给验证实现,在大多数情况下是 Hibernate。 invocation.getArguments() 将包含所有已使用给定值初始化的方法参数,无论验证注释如何。

【讨论】:

以上是关于JSR 303 Bean 验证 - 为啥使用 getter 而不是 setter?的主要内容,如果未能解决你的问题,请参考以下文章

JSR 303 Bean 验证 + Javascript 客户端验证

Wildfly:ExceptionMapper 未通过 RestEasy JSR-303 Bean 验证触发

带有 i18n 消息的 Spring-MVC + RESTeasy 表单 bean 验证 (JSR 303)

SpringMVC中的 JSR 303 数据校验框架说明

JSR 303标准

JSR-303 Bean Validation 介绍及 Spring MVC 服务端验证最佳实践