We have been recently working a lot on the Bean Validation spec (JSR 303) and have two good news for you:
- the bootstrap API proposal is out
- the reference implementation is available too (end of this blog)
Please have a look at both and give us feedbacks. It is still time to make it better ;)
Bootstrap API
The primary goal of the bootstrap API is trivial. Provide access to a ValidatorFactory capable of building Validator instances. These validator instances are then used to validate the domain model.
Some additional goals have been pursued as well:
- simple to use
- type safe
- extensible and flexible to the container environment (Java EE, Java SE, dependency injection framework, OSGi-esque containers and so on)
- support multiple implementations
Examples
The best way to learn an API is to see it in action.
Everyday bootstrap
The first example shows the most simple way and also the most common.
ValidatorFactory factory = Validation.getValidatorBuilder().build(); //cache the factory somewhere Validator<Address> addressValidator = factory.getValidator(Address.class);
This creates a thread-safe ValidatorFactory object that should be cached. In this example, the default Bean Validation provider is used unless an explicit provider implementation is defined in the Bean Validation XML configuration file.
Container driven bootstrap
The second example refines some of the configuration elements.
ValidatorFactory factory = Validation .getValidatorBuilder() .messageResolver( new WebBeansMessageResolver() ) .constraintFactory( new WebBeansComponentConstraintFactory() ) .build(); //cache the factory somewhere Validator<Address> addressValidator = factory.getValidator(Address.class);
This example shows a typical bootstrap in a container. The container has the ability to refined the message resolution strategy to adhere it standards. In the case of Web Bean, one can imagine the message resolver to resolve contextual components and EL expressions.
A container is also responsible for the lifecycle of its components. A custom contraint implementation factory can be provided. It will be responsible for instantiating constraint implementations. In the case of Web Beans, one can imagine a constraint factory properly injecting components inside the constraint implementation.
Some containers change the standard Java rules when it comes to classloader and resource discovery. It can make Bean Validation provider discovery challenging in such environments. To work around this problem, the specification lets a container override the provider resolution strategy. This strategy can be injected at bootstrap time.
//OSGi environment is picky when it comes to class loaders. ValidatorFactory factory = Validation .defineBootstrapState() .providerResolver( new OSGiServiceDiscoverer() ) .build(); //cache the factory somewhere Validator<Address> addressValidator = factory.getValidator(Address.class);
OSGIServiceDiscoverer has the knowledge of the OSGi isolation rules and can resolve the list of available providers accordingly.
Specific provider bootstrap
The third example shows how to select a specific provider programmatically. Each provider is uniquely identified by a sub interface of ValidatorBuilder. Hibernate Validator for example provides org.hibernate.validator.HibernateValidatorBuilder.
//get Hibernate Validator provider ValidatorFactory factory = Validation .builderType( HibernateValidatorBuilder.class ) .getValidatorBuilder() .build(); //cache the factory somewhere Validator<Address> addressValidator = factory.getValidator(Address.class);
Using a specific sub interface of ValidatorBuilder as unique identifier has an other advantage. This sub interface can host provider specific configuration and still be called in a type safe way.
HibernateValidatorBuilder hibernateBuilder = Validation .builderType( HibernateValidatorBuilder.class ) .getValidatorBuilder(); ValidatorFactory factory = hibernateBuilder .messageResolver( new ContainerMessageResolver() ) //default configuration option .disableDDLAlteration() .enableConstraintHotRedeploy() .build();
Or written in a more compact way
ValidatorFactory factory = Validation .builderType( HibernateValidatorBuilder.class ) .getValidatorBuilder() .messageResolver( new ContainerMessageResolver() ) .disableDDLAlteration() .enableConstraintHotRedeploy() .build();
Where HibernateValidatorBuilder looks like:
public interface HibernateValidatorBuilder extends ValidatorBuilder<HibernateValidatorBuilder> { HibernateValidatorBuilder disableDDLAlteration(); HibernateValidatorBuilder enableconstraintHotRedeploy(); }
Note that nowhere we needed to down cast objects!
Main APIs
The main artifacts involved in the bootstrap process are:
Validation: API entry point. Lets you optionally define the Bean Validation provider targeted as well as a provider resolution strategy. Validation generates ValidatorBuilder objects and can bootstrap any provider implementation.
ValidationProvider: contract between the bootstrap procedure and a Bean Validation provider implementation.
ValidationProviderResolver: returns a list of all Bean Validation providers available in the execution context (generally the classpath).
ValidatorBuilder: collects the configuration details that will be used to build ValidatorFactory. A specific sub interface of ValidatorBuilder must be provided by Bean Validation providers as a unique identifier. This sub interface typically hosts provider specific configurations.
ValidatorFactory: result of the bootstrap process. Build Validator instances from a given Bean Validation provider. This object is thread-safe.
Specification
The bits of specification describing the bootstrap process is available here[1] and the APIs are available as part of the reference implementation. Please provide feedback either to our forum or in the JIRA issue tracker project component spec-general.
Reference implementation
The reference implementation is available in SVN. Simply do
svn checkout http://anonsvn.jboss.org/repos/hibernate/validator/trunk/ rito check it out so to speak. The spec is comprised of the validation API and the actual reference implementation. Both projects are Maven projects. They are distributed under the Apache Software License 2.0.
Many thanks to Hardy for taking over my bits and pieces of prototype, todos and complaints and make it an actual project. Hardy will probably write a blog entry sometimes in the future about the RI architecture.
You can provide feedback to our forum. If you have suggestions or bug reports, a JIRA issue tracker project has also been created.
It is still a work in progress but is good enough to start playing with it. Most of the ideas behind the spec are already present, so have a look!