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

关于这个文档,我明白如果我的GroupService实现了GroupManager并覆盖了它的方法,那么我不能用验证约束来注释,因为Hibernate验证器不允许它(这被证明是Liskov替换原理)。 我的意思是做类似的事情

public class GroupService implements GroupManager{

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

然后会引发ConstraintDeclarationException ,对吧? 所以解决方案显然是将这些限制放在界面上,但在这种情况下:

  • 我可能无法访问修改接口(如GroupManager属于Spring Security )。 我该怎么做呢?
  • 我认为这些验证约束不应该影响接口,因为它们是其实现的一部分,所以如果我想要其他服务实现,我不应该将它与这些验证联系起来。 也许这个新的我想实现另一种验证, Hibernate Validator迫使我“弄脏”界面

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

    您可以使用xml配置,因为JSR-303(Bean验证)支持它。 例如

    <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文档中的xml配置一章。

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

    正如hibernate文档所述

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

    子类型不应加强方法前提条件。 如果你说你的子类型GroupService不允许一个null参数,你可能会加强前提条件。 例如,使用GroupManager的客户端可能不知道(也不应该知道)它是GroupServiceGroupManager界面不会对参数进行任何限制。 所以,如果你这样做,你打破了以前的客户代码。 这违反了Liskov替代原则。

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

    一般来说...当我定义方法时,我会应用这些规则

  • 如果一个方法定义了一个参数,那么它不能为null
  • 如果参数是可选的 - 创建重载方法并在内部处理可选参数。 例如通过使用空对象模式。
  • 这些简单的规则帮助我为客户创建一个清晰的API。

    编辑

    我认为可能我有impl“A”和impl“B”(都实现相同的接口),其中impl“A”比“B”有更多(和不同的)验证。

    如果是这样,他们不具有相同的接口或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();
    

    以前合法的客户端代码不再适用。

    我只是通过这个例子来展示合同和方法签名之间的区别。

    这里可以找到详细而且非常好的解释。

    由于GroupManager javadoc不限制参数,合法的impl必须处理每种情况'? 这是验证方法内的参数?

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

    链接地址: http://www.djcxy.com/p/86649.html

    上一篇: How to validate overridden methods parameters with Hibernate Validator?

    下一篇: Why doesn't C++ support dynamic arrays on the stack?