Hibernate.orgCommunity Documentation

第 5 章 Bootstrapping

5.1. Configuration 和 ValidatorFactory
5.2. ValidationProviderResolver
5.3. MessageInterpolator
5.3.1. ResourceBundleLocator
5.4. TraversableResolver
5.5. ConstraintValidatorFactory

第 5.1 节 “Configuration 和 ValidatorFactory”中我们说道过, 最简单的创建一个Validator实例的方法是通过Validation.buildDefaultValidatorFactory. 在本章中我们会继续介绍javax.validation.Validation中的其他方法, 以及如何通过这些方法在Bean Validation初始化的时候对其进行配置的.

The different bootstrapping options allow, amongst other things, to bootstrap any Bean Validation implementation on the classpath. 通常, 一个服务的提供者是能够被Java Service Provider发现的. 对于Bean Validation的实现(服务提供者)来说, 他们的META-INF/services目录下需要包含一个名为javax.validation.spi.ValidationProvider的文件. 此文件中包含了一个ValidationProvider接口的实现类的全路径名称, 具体到Hibernate Validator来说, 就是org.hibernate.validator.HibernateValidator.

注意

如果当前类路径下存在多个Bean Validation的实现, 那么Validation.buildDefaultValidatorFactory()并不能保证具体那个实现会被使用. 如果想指定某一个的话, 请使用Validation.byProvider().

Validation类提供了三种方法来创建一个Validator的实例, 例 5.1 “Validation.buildDefaultValidatorFactory()”中显示的是最简单的方法.


你也可以通过Validation.byDefaultProvider()现获取一个Configuration对象, 这样可以对要创建的Validator进行配置.


MessageInterpolator, TraversableResolverConstraintValidatorFactory会在后面详细介绍.

最后, 你可以指定使用哪个Bean Validation的实现. 如果类路径下存在多个Bean Validation的实现的话,这样就很有必要了. 例如, 如果你想使用Hibernate Validator来作为内部实现来创建Validator的话:


提示

创建出来的Validator实例是线程安全的, 所以你可以把它缓存起来.

如果 Java Service Provider机制在你的环境中不能够正常工作, 或者你有特别的classloader设置的话, 你也可以提供一个自定义的ValidationProviderResolver.例 5.4 “使用自定义的ValidationProviderResolver”显示了如何在OSGi环境中插入自定义的provider resolver.


在这种情况下, 你的OSGiServiceDiscoverer类需要实现ValidationProviderResolver接口:


第 2.2.4 节 “验证失败提示信息解析” already discussed the default message interpolation algorithm. If you have special requirements for your message interpolation you can provide a custom interpolator using Configuration.messageInterpolator(). This message interpolator will be shared by all validators generated by the ValidatorFactory created from this Configuration. 例 5.6 “自定义的MessageInterpolator” shows an interpolator (available in Hibernate Validator) which can interpolate the value being validated in the constraint message. To refer to this value in the constraint message you can use:

  • ${validatedValue}: this will call String.valueOf on the validated value.

  • ${validatedValue:<format>}: provide your own format string which will be passed to String.format together with the validated value. Refer to the javadoc of String.format for more information about the format options.


提示

It is recommended that MessageInterpolator implementations delegate final interpolation to the Bean Validation default MessageInterpolator to ensure standard Bean Validation interpolation rules are followed. The default implementation is accessible through Configuration.getDefaultMessageInterpolator().

到目前位置我们还没有讨论过TraversableResolver接口, 它的设计目的是在某些情况下, 我们可能不应该去获取一个属性的状态. 最典型的情况就是一个延迟加载的属性或者与JPA中涉及到关联关系的时候. 当验证这两种情况的属性的时候, 很可能会触发一次对数据库的查询.Bean Validation正是通过TraversableResolver接口来控制能否访问某一个属性的 (例 5.8 “TraversableResolver接口”).

例 5.8. TraversableResolver接口

/**

 * Contract determining if a property can be accessed by the Bean Validation provider
 * This contract is called for each property that is being either validated or cascaded.
 *
 * A traversable resolver implementation must be thread-safe.
 *
 */
public interface TraversableResolver {
    /**
     * Determine if the Bean Validation provider is allowed to reach the property state
     *
     * @param traversableObject object hosting <code>traversableProperty</code> or null  
     *                          if validateValue is called
     * @param traversableProperty the traversable property.
     * @param rootBeanType type of the root object passed to the Validator.
     * @param pathToTraversableObject path from the root object to
     *        <code>traversableObject</code>
     *        (using the path specification defined by Bean Validator).
     * @param elementType either <code>FIELD</code> or <code>METHOD</code>.
     *
     * @return <code>true</code> if the Bean Validation provider is allowed to
     *         reach the property state, <code>false</code> otherwise.
     */
     boolean isReachable(Object traversableObject,
                         Path.Node traversableProperty,
                         Class<?> rootBeanType,
                         Path pathToTraversableObject,
                         ElementType elementType);
    /**
     * Determine if the Bean Validation provider is allowed to cascade validation on
     * the bean instance returned by the property value
     * marked as <code>@Valid</code>.
     * Note that this method is called only if isReachable returns true for the same set of
     * arguments and if the property is marked as <code>@Valid</code>
     *
     * @param traversableObject object hosting <code>traversableProperty</code> or null
     *                          if validateValue is called
     * @param traversableProperty the traversable property.
     * @param rootBeanType type of the root object passed to the Validator.
     * @param pathToTraversableObject path from the root object to
     *        <code>traversableObject</code>
     *        (using the path specification defined by Bean Validator).
     * @param elementType either <code>FIELD</code> or <code>METHOD</code>.
     *
     * @return <code>true</code> if the Bean Validation provider is allowed to
     *         cascade validation, <code>false</code> otherwise.
     */
     boolean isCascadable(Object traversableObject,
                          Path.Node traversableProperty,
                          Class<?> rootBeanType,
                          Path pathToTraversableObject,
                          ElementType elementType);
}

Hibernate Validator provides two TraversableResolvers out of the box which will be enabled automatically depending on your environment. The first is the DefaultTraversableResolver which will always return true for isReachable() and isTraversable(). The second is the JPATraversableResolver which gets enabled when Hibernate Validator gets used in combination with JPA 2. In case you have to provide your own resolver you can do so again using the Configuration object as seen in 例 5.9 “自定义的TraversableResolver”.


最后, 还有个配置项得提一下, 那就是ConstraintValidatorFactory类. Hibernate Validator中默认的ConstraintValidatorFactory需要一个无参的构造方法来初始化ConstraintValidator的实例(参考第 3.1.2 节 “约束校验器”). 对于自定义的ConstraintValidatorFactory实现来说, 例如, 你可以让其支持对约束条件的依赖注入等功能. 配置使用这个自定义的ConstraintValidatorFactory的方法还是老样子(例 5.10 “自定义的ConstraintValidatorFactory”).


你需要实现此接口:


警告

如果一个约束条件的实现需要依赖ConstraintValidatorFactory的某个特定的行为(例如依赖注入或者没有无参的构造方法等) 都可能导致不可移植.

注意

ConstraintValidatorFactory不应该缓存其创建的实例, 因为每个实例都可能在其的初始化方法中被修改.