Hibernate.orgCommunity Documentation
In Section 2.2.1, “Obtaining a Validator instance” you already saw one
way for creating a Validator
instance - via
Validation#buildDefaultValidatorFactory()
. In this
chapter you will learn how to use the other methods in
javax.validation.Validation
in order to bootstrap
specifically configured validators.
You obtain a Validator
by retrieving a
ValidatorFactory
via one of the static methods on
javax.validation.Validation
and calling
getValidator()
on the factory instance.
Example 8.1, “Bootstrapping default ValidatorFactory and Validator” shows how to obtain a validator from the default validator factory:
Example 8.1. Bootstrapping default ValidatorFactory
and
Validator
ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
Validator validator = factory.getValidator();
The generated ValidatorFactory
and
Validator
instances are thread-safe and can be
cached. As Hibernate Validator uses the factory as context for caching
constraint metadata it is recommended to work with one factory instance
within an application.
Bean Validation supports working with several providers such as
Hibernate Validator within one application. If more than one provider is
present on the classpath, it is not guaranteed which one is chosen when
creating a factory via
buildDefaultValidatorFactory()
.
In this case you can explicitly specify the provider to use via
Validation#byProvider()
, passing the provider's
ValidationProvider
class as shown in Example 8.2, “Bootstrapping ValidatorFactory and
Validator using a specific provider”.
Example 8.2. Bootstrapping ValidatorFactory
and
Validator
using a specific provider
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Note that the configuration object returned by
configure()
allows to specifically customize the
factory before calling buildValidatorFactory()
.
The available options are discussed later in this chapter.
Similarly you can retrieve the default validator factory for configuration which is demonstrated in Example 8.3, “Retrieving the default ValidatorFactory for configuration”.
Example 8.3. Retrieving the default ValidatorFactory
for configuration
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
If a ValidatorFactory
instance is no longer
in use, it should be disposed by calling
ValidatorFactory#close()
. This will free any
resources possibly allocated by the factory.
By default, available Bean Validation providers are discovered using the Java Service Provider mechanism.
For that purpose, each provider includes the file
META-INF/services/javax.validation.spi.ValidationProvider
,
containing the fully qualified classname of its
ValidationProvider
implementation. In the case of
Hibernate Validator this is
org.hibernate.validator.HibernateValidator
.
Depending on your environment and its classloading specifics,
provider discovery via the Java's service loader mechanism might not
work. In this case you can plug in a custom
ValidationProviderResolver
implementation which
performs the provider retrieval. An example is OSGi, where you could
implement a provider resolver which uses OSGi services for provider
discovery.
To use a custom provider resolver pass it via
providerResolver()
as shown shown in Example 8.4, “Using a custom
ValidationProviderResolver”.
Example 8.4. Using a custom
ValidationProviderResolver
package org.hibernate.validator.referenceguide.chapter08;
public class OsgiServiceDiscoverer implements ValidationProviderResolver {
@Override
public List<ValidationProvider<?>> getValidationProviders() {
//...
}
}
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.providerResolver( new OsgiServiceDiscoverer() )
.configure()
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
By default validator factories retrieved from
Validation
and any validators they create are
configured as per the XML descriptor
META-INF/validation.xml
(see Chapter 7, Configuring via XML), if present.
If you want to disable the XML based configuration, you can do so by
invoking
Configuration#ignoreXmlConfiguration()
.
The different values of the XML configuration can be accessed via
Configuration#getBootstrapConfiguration()
. This
can for instance be helpful if you want to integrate Bean Validation into
a managed environment and want to create managed instances of the objects
configured via XML.
Using the fluent configuration API, you can override one or more of
the settings when bootstrapping the factory. The following sections show
how to make use of the different options. Note that the
Configuration
class exposes the default
implementations of the different extension points which can be useful if
you want to use these as delegates for your custom implementations.
Message interpolators are used by the validation engine to create user readable error messages from constraint message descriptors.
In case the default message interpolation algorithm described in
Chapter 4, Interpolating constraint error messages is not sufficient for
your needs, you can pass in your own implementation of the
MessageInterpolator
interface via
Configuration#messageInterpolator()
as shown in
Example 8.5, “Using a custom
MessageInterpolator”.
Example 8.5. Using a custom
MessageInterpolator
package org.hibernate.validator.referenceguide.chapter08;
public class MyMessageInterpolator implements MessageInterpolator {
@Override
public String interpolate(String messageTemplate, Context context) {
//...
}
@Override
public String interpolate(String messageTemplate, Context context, Locale locale) {
//...
}
}
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.messageInterpolator( new MyMessageInterpolator() )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
In some cases the validation engine should not access the state of a bean property. The most obvious example for that is a lazily loaded property or association of a JPA entity. Validating this lazy property or association would mean that its state would have to be accessed, triggering a load from the database.
Which properties can be accessed and which ones not is controlled
by querying the TraversableResolver
interface.
Example 8.6, “Using a custom
TraversableResolver” shows how to
use a custom traversable resolver implementation.
Example 8.6. Using a custom
TraversableResolver
package org.hibernate.validator.referenceguide.chapter08;
public class MyTraversableResolver implements TraversableResolver {
@Override
public boolean isReachable(
Object traversableObject,
Node traversableProperty,
Class<?> rootBeanType,
Path pathToTraversableObject,
ElementType elementType) {
//...
}
@Override
public boolean isCascadable(
Object traversableObject,
Node traversableProperty,
Class<?> rootBeanType,
Path pathToTraversableObject,
ElementType elementType) {
//...
}
}
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.traversableResolver( new MyTraversableResolver() )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Hibernate Validator provides two
TraversableResolver
s out of the box which will be
enabled automatically depending on your environment. The first is
DefaultTraversableResolver
which will always
return true
for
isReachable()
and
isTraversable()
. The second is
JPATraversableResolver
which gets enabled when
Hibernate Validator is used in combination with JPA 2.
ConstraintValidatorFactory
is the extension
point for customizing how constraint validators are instantiated and
released.
The default ConstraintValidatorFactory
provided by Hibernate Validator requires a public no-arg constructor to
instantiate ConstraintValidator
instances (see
Section 6.1.2, “The constraint
validator”). Using a custom
ConstraintValidatorFactory
offers for example the
possibility to use dependency injection in constraint validator
implementations.
To configure a custom constraint validator factory call
Configuration#constraintValidatorFactory()
(see
Example 8.7, “Using a custom
ConstraintValidatorFactory”.
Example 8.7. Using a custom
ConstraintValidatorFactory
package org.hibernate.validator.referenceguide.chapter08;
public class MyConstraintValidatorFactory implements ConstraintValidatorFactory {
@Override
public <T extends ConstraintValidator<?, ?>> T getInstance(Class<T> key) {
//...
}
@Override
public void releaseInstance(ConstraintValidator<?, ?> instance) {
//...
}
}
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.constraintValidatorFactory( new MyConstraintValidatorFactory() )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Any constraint implementations relying on
ConstraintValidatorFactory
behaviors specific
to an implementation (dependency injection, no no-arg constructor and
so on) are not considered portable.
ConstraintValidatorFactory
implementations should not cache validator instances as the state of
each instance can be altered in the
initialize()
method.
In case a method or constructor parameter constraint is violated,
the ParameterNameProvider
interface is used to
retrieve the parameter's name and make it available to the user via the
constraint violation's property path.
The default implementation returns parameter names in the form
arg0
, arg1
etc., while custom
implementations could e.g. be based on parameter annotations, debug
symbols or a feature for retrieving parameter names at runtime possibly
provided by future Java versions.
Custom ParameterNameProvider
implementations are used as demonstrated in Example 8.8, “Using a custom
ParameterNameProvider”.
Example 8.8. Using a custom
ParameterNameProvider
package org.hibernate.validator.referenceguide.chapter08;
public class MyParameterNameProvider implements ParameterNameProvider {
@Override
public List<String> getParameterNames(Constructor<?> constructor) {
//...
}
@Override
public List<String> getParameterNames(Method method) {
//...
}
}
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.parameterNameProvider( new MyParameterNameProvider() )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Hibernate Validator comes with a custom
ParameterNameProvider
implementation based on
the ParaNamer
library which provides several ways for obtaining parameter names at
runtime. Refer to Section 11.7, “ParaNamer based
ParameterNameProvider” to learn more
about this specific implementation.
As discussed earlier you can configure the constraints applying for your Java beans using XML based constraint mappings.
Besides the mapping files specified in
META-INF/validation.xml
you can add further
mappings via Configuration#addMapping()
(see
Example 8.9, “Adding constraint mapping streams”). Note that the passed
input stream(s) must adhere to the XML schema for constraint mappings
presented in Section 7.2, “Mapping constraints via
constraint-mappings”.
Example 8.9. Adding constraint mapping streams
InputStream constraintMapping1 = ...;
InputStream constraintMapping2 = ...;
ValidatorFactory validatorFactory = Validation.byDefaultProvider()
.configure()
.addMapping( constraintMapping1 )
.addMapping( constraintMapping2 )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
You should close any passed input stream after the validator factory has been created.
Via the configuration object returned by
Validation#byProvider()
provider specific
options can be configured.
In case of Hibernate Validator this e.g. allows you to enable the fail fast mode and pass one or more programmatic constraint mappings as demonstrated in Example 8.10, “Setting Hibernate Validator specific options”.
Example 8.10. Setting Hibernate Validator specific options
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.failFast( true )
.addMapping( (ConstraintMapping) null )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Alternatively, provider-specific options can be passed via
Configuration#addProperty()
. Hibernate
Validator supports enabling the fail fast mode that way, too:
Example 8.11. Enabling a Hibernate Validator specific option via
addProperty()
ValidatorFactory validatorFactory = Validation.byProvider( HibernateValidator.class )
.configure()
.addProperty( "hibernate.validator.fail_fast", "true" )
.buildValidatorFactory();
Validator validator = validatorFactory.getValidator();
Refer to Section 11.2, “Fail fast mode” and Section 11.3, “Programmatic constraint declaration” to learn more about the fail fast mode and the constraint declaration API.
When working with a configured validator factory it can occasionally
be required to apply a different configuration to a single
Validator
instance. Example 8.12, “Configuring a Validator via
usingContext()” shows how this can be achieved by
calling ValidatorFactory#usingContext()
.
Example 8.12. Configuring a Validator
via
usingContext()
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.usingContext()
.messageInterpolator( new MyMessageInterpolator() )
.traversableResolver( new MyTraversableResolver() )
.getValidator();
Copyright © 2009 - 2013 Red Hat, Inc. & Gunnar Morling