Hibernate.orgCommunity Documentation
在第 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. Generally, an available provider is discovered by the Java Service Provider mechanism. A Bean Validation implementation includes the file javax.validation.spi.ValidationProvider
in META-INF/services
. This file contains the fully qualified classname of the ValidationProvider
of the implementation. In the case of Hibernate Validator this is org.hibernate.validator.HibernateValidator
.
如果当前类路径下存在多个Bean Validation的实现, 那么Validation.buildDefaultValidatorFactory()
并不能保证具体那个实现会被使用. 如果想指定某一个的话, 请使用Validation.byProvider()
.
Validation类提供了三种方法来创建一个Validator的实例, 例 5.1 “Validation.buildDefaultValidatorFactory()”中显示的是最简单的方法.
例 5.1. Validation.buildDefaultValidatorFactory()
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
你也可以通过Validation.byDefaultProvider()
现获取一个Configuration对象, 这样可以对要创建的Validator进行配置.
例 5.2. Validation.byDefaultProvider()
Configuration<?> config = Validation.byDefaultProvider().configure();
config.messageInterpolator(new MyMessageInterpolator())
.traversableResolver( new MyTraversableResolver())
.constraintValidatorFactory(new MyConstraintValidatorFactory());
ValidatorFactory factory = config.buildValidatorFactory();
Validator validator = factory.getValidator();
MessageInterpolator
, TraversableResolver
和 ConstraintValidatorFactory
会在后面详细介绍.
最后, 你可以指定使用哪个Bean Validation的实现. 如果类路径下存在多个Bean Validation的实现的话,这样就很有必要了. 例如, 如果你想使用Hibernate Validator来作为内部实现来创建Validator
的话:
例 5.3. Validation.byProvider( HibernateValidator.class )
HibernateValidatorConfiguration config = Validation.byProvider( HibernateValidator.class ).configure();
config.messageInterpolator(new MyMessageInterpolator())
.traversableResolver( new MyTraversableResolver())
.constraintValidatorFactory(new MyConstraintValidatorFactory());
ValidatorFactory factory = config.buildValidatorFactory();
Validator validator = factory.getValidator();
创建出来的Validator
实例是线程安全的, 所以你可以把它缓存起来.
如果 Java Service Provider机制在你的环境中不能够正常工作, 或者你有特别的classloader设置的话, 你也可以提供一个自定义的ValidationProviderResolver
.例 5.4 “使用自定义的ValidationProviderResolver”显示了如何在OSGi环境中插入自定义的provider resolver.
例 5.4. 使用自定义的ValidationProviderResolver
Configuration<?> config = Validation.byDefaultProvider()
.providerResolver( new OSGiServiceDiscoverer() )
.configure();
ValidatorFactory factory = config.buildValidatorFactory();
Validator validator = factory.getValidator();
在这种情况下, 你的OSGiServiceDiscoverer
类需要实现ValidationProviderResolver
接口:
例 5.5. ValidationProviderResolver接口
public interface ValidationProviderResolver {
/**
* Returns a list of ValidationProviders available in the runtime environment.
*
* @return list of validation providers.
*/
List<ValidationProvider<?>> getValidationProviders();
}
第 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.
例 5.6. 自定义的MessageInterpolator
Configuration<?> configuration = Validation.byDefaultProvider().configure();
ValidatorFactory factory = configuration
.messageInterpolator(new ValueFormatterMessageInterpolator(configuration.getDefaultMessageInterpolator()))
.buildValidatorFactory();
Validator validator = factory.getValidator();
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()
.
一个普遍的需求是你可能需要为错误消息解析指定你自己的resource bundles. ResourceBundleMessageInterpolator
是Hibernate Validator中默认的MessageInterpolator
的实现, 它默认情况下是通过ResourceBundle.getBundle
来获取resource bundle的. 不过, ResourceBundleMessageInterpolator
也支持你指定一个自定义的ResourceBundleLocator
实现来提供你自己的resource bundle. 例 5.7 “自定义的ResourceBundleLocator”提供了一个示例. 在这个例子中, 先通过 HibernateValidatorConfiguration.getDefaultResourceBundleLocator
获取默认的ResourceBundleLocator
实现, 然后再用你自定义的实现把默认的包装起来, 代理模式.
例 5.7. 自定义的ResourceBundleLocator
HibernateValidatorConfiguration configure = Validation.byProvider(HibernateValidator.class).configure();
ResourceBundleLocator defaultResourceBundleLocator = configure.getDefaultResourceBundleLocator();
ResourceBundleLocator myResourceBundleLocator = new MyCustomResourceBundleLocator(defaultResourceBundleLocator);
configure.messageInterpolator(new ResourceBundleMessageInterpolator(myResourceBundleLocator));
Hibernate Validator提供了两个ResourceBundleLocator
的实现 - PlatformResourceBundleLocator
(默认) 和 AggregateResourceBundleLocator
. 后者可以定义一系列的resource bundle, 然后它会读取这些文件, 并且把它们组合成一个. 更多信息请参考此类的javadoc 文档.
到目前位置我们还没有讨论过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 TraversableResolver
s 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”.
例 5.9. 自定义的TraversableResolver
Configuration<?> configuration = Validation.byDefaultProvider().configure();
ValidatorFactory factory = configuration
.traversableResolver(new MyTraversableResolver())
.buildValidatorFactory();
Validator validator = factory.getValidator();
最后, 还有个配置项得提一下, 那就是ConstraintValidatorFactory
类. Hibernate Validator中默认的ConstraintValidatorFactory
需要一个无参的构造方法来初始化ConstraintValidator
的实例(参考第 3.1.2 节 “约束校验器”). 对于自定义的ConstraintValidatorFactory
实现来说, 例如, 你可以让其支持对约束条件的依赖注入等功能. 配置使用这个自定义的ConstraintValidatorFactory
的方法还是老样子(例 5.10 “自定义的ConstraintValidatorFactory”).
例 5.10. 自定义的ConstraintValidatorFactory
Configuration<?> configuration = Validation.byDefaultProvider().configure();
ValidatorFactory factory = configuration
.constraintValidatorFactory(new IOCConstraintValidatorFactory())
.buildValidatorFactory();
Validator validator = factory.getValidator();
你需要实现此接口:
例 5.11. ConstraintValidatorFactory接口
public interface ConstraintValidatorFactory {
/**
* @param key The class of the constraint validator to instantiate.
*
* @return A constraint validator instance of the specified class.
*/
<T extends ConstraintValidator<?,?>> T getInstance(Class<T> key);
}
如果一个约束条件的实现需要依赖ConstraintValidatorFactory
的某个特定的行为(例如依赖注入或者没有无参的构造方法等) 都可能导致不可移植.
ConstraintValidatorFactory不应该缓存其创建的实例, 因为每个实例都可能在其的初始化方法中被修改.
版权 © 2009 - 2011 Red Hat, Inc. & Gunnar Morling