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();
If no specific traversable resolver has been configured, the default behavior is to consider all properties as reachable and cascadable. When using Hibernate Validator together with a JPA 2 provider such as Hibernate ORM, only those properties will be considered reachable which already have been loaded by the persistence provider and all properties will be considered cascadable.
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 name and make it available to the user via the
property path of the constraint violation.
The default implementation returns parameter names in the form of arg0
, arg1
etc, while custom
implementations can retrieve the parameter names using methods such as parameter annotations,
debug symbols, or Java 8 reflection.
An implementation for retrieving the parameter names using reflection in Java 8 is provided with
ReflectionParameterNameProvider
. For this parameter name provider to work, the
source must be compiled using the –parameters
compiler argument. Otherwise, the provider will
return synthetic names in the form of arg0
, arg1
, etc.
To use ReflectionParameterNameProvider
or another custom provider either pass an instance of
the provider during bootstrapping as shown in Example 8.8, “Using a custom ParameterNameProvider
”,
or specify the fully qualified class name of the provider as value for
the <parameter-name-provider>
element in the META-INF/validation.xml file
(see Section 7.1, “Configuring the validator factory in validation.xml”). This is 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.10, “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
instance via usingContext()
” shows how this can
be achieved by calling ValidatorFactory#usingContext()
.
Example 8.12. Configuring a Validator
instance via usingContext()
ValidatorFactory validatorFactory = Validation.buildDefaultValidatorFactory();
Validator validator = validatorFactory.usingContext()
.messageInterpolator( new MyMessageInterpolator() )
.traversableResolver( new MyTraversableResolver() )
.getValidator();