如何使用Hibernate Validator验证重写的方法参数?

时间:2015-07-16 18:35:39

标签: java validation constraints hibernate-validator

关于this doc我理解如果我有我的GroupService实现GroupManager并覆盖它的方法,那么我不能用验证约束进行注释,因为Hibernate Validator不允许它(结果是已知的)作为Liskov substitution principle)。我的意思是做像

这样的事情
public class GroupService implements GroupManager{

    @Override
    public List<String> findUsersInGroup(@NotNull String groupName) {
        ...
    }
}

然后会提出ConstraintDeclarationException,对吧?因此,解决方案显然是将这些约束放在接口上,但在这种情况下:

  1. 我可能无法访问modname接口(因为GroupManager属于Spring Security的情况)。我怎么能这样做?
  2. 我认为这些验证限制不应该影响接口,因为它们是其实现的一部分,所以如果我想要有任何其他服务实现,我不应该把它连接到这些验证。也许有了这个新的,我想要实现另一种验证,Hibernate Validator迫使我去弄脏&#39;界面

1 个答案:

答案 0 :(得分:4)

  

我可能无法访问modificate接口(因为这种情况下GroupManager属于Spring Security)。在这种情况下我该怎么做?

您可以使用xml配置,因为JSR-303(Bean Validation)支持它。 E.g。

<constraint-mappings xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                     xsi:schemaLocation="http://jboss.org/xml/ns/javax/validation/mapping validation-mapping-1.0.xsd"
                     xmlns="http://jboss.org/xml/ns/javax/validation/mapping">
    <default-package>org.springframework.security.provisioning</default-package>
    <bean class="GroupManager" ignore-annotations="true">
        <method name="findUsersInGroup">
            <parameter type="java.lang.String">
                <constraint annotation="javax.validation.constraints.NotNull"/>
            </parameter>
        </method>
    </bean>
</constraint-mappings>

请参阅hibernate doc中的xml配置章节。

  

我认为这些验证约束不应该影响接口,因为它们是其实现的一部分

正如hibernate文档所说

  

当在子类型中重写方法时,方法参数约束只能在基类型中声明。这种限制的原因是类型客户端要满足的前提条件不能在子类型中加强(基本类型甚至可能都不知道)客户端)。

不应通过子类型来加强方法前提条件。如果您说您的子类型GroupService不允许使用null参数,则可能会加强前提条件。例如。使用GroupManager的客户可能不知道(也不应该知道)它是GroupServiceGroupManager接口不对参数进行任何限制。因此,如果你这样做,你打破以前的leagal客户端代码。这违反了Liskov substitution principle

遗憾的是GroupManager javadoc不限制参数。因此,法律实施必须处理所有情况。

一般而言......当我定义方法时,我应用这些规则

  • 如果方法定义了参数,则它不能是null
  • 如果参数是可选的 - 创建重载方法并在内部处理可选参数。例如。使用null object pattern

这些简单的规则帮助我为客户创建一个明确的api。

修改

  

我认为我可能会有一个&#34; A&#34;和impl&#34; B&#34; (两者都实现相同的界面)其中impl&#34; A&#34;比&#34; B&#34;

有更多(和不同)的验证

如果是这样,他们没有相同的界面或api。你看到的是两者都有相同的方法签名。但是两个相同的方法签名不能共享相同的api合同。当我谈论一个界面时,我会想到合同 而不仅仅是签名。想象一下以下界面:

public class Container {

    /**
     * @return a non-empty collection of elements. 
     */
     public Collection<Element> getElements();
}

在这种情况下,合法客户端代码将是

Container container = ....;
Element firstElement = container.getElements().iterator().next();

因为合同说它返回非空集合。

如果我们改变了javadoc,那么后期条件......

 /**
  * @return a collection of elements. 
  */
  public Collection<Element> getElements();

以前合法的客户代码将不再有效。

我刚刚做了这个例子,向您展示合同和方法签名之间的区别。

可以找到详细而且非常好的解释here

  

由于GroupManager javadoc不限制参数,因此合法的impl必须处理所有情况&#39;?这是在方法中验证参数吗?

是。如果接口没有对参数添加任何限制,则实现必须处理每个状态,因为客户端可能会传递参数 在任何州。