The naming in the bootstrap API was lacking some consistency and was a bit obscure at time
I went back to the drawing board and came with something that is I think more natural and thus easier to use:
- to build ValidatorFactory
- to build Validator
Each set of proposal change is followed by the old and new syntax. Feedback welcome.
To Build a ValidatorFactory
Here are the proposed changes
Code:
ValidatorFactoryBuilder => Configuration (should it be ValidatorFactoryConfiguration)
Validation.builderType(Class<T>) to Validation.byProvider(Class<T>)
Validation.defineBootstrapState() to Validation.byDefaultProvider()
GenericBuilderFactory.getBuilder() to GenericConfigurationFactory.configure()
SpecializedBuilderFactory.getBuilder() to SpecializedConfigurationFactory.configure()
ValidatorFactoryBuilder.build() to Configuration.getValidatorFactory() (should it be buildValidatorFactory()?)
ValidatorFactoryBuilder.configure() to Configuration.customConfiguration()
Also I am considering:
- removing Validation.getBuilder() (which would have been Validation.configure() )
- adding Validation.getDefaultValidatorFactory() (which correspond to the default bootstrap strategy used by JPA and JSF unless overridden)
Here are various bootstraps with the old naming followed by the new naming. You will see that we gain in consistency and expressivity:
- byProvider(Class<?>) vs byDefaultProvider()
- the object type retrieved and its purpose is more obvious (configure(), getValidatorFactory())
- the builder is a configuration object retrieving state to build ValidatorFactory
Code:
//simple bootstrap
ValidatorFactoryBuilder<?> builder = Validation.getBuilder();
=> no equivalent but replaced by
Configuration<?> configuration = Validation.byDefaultProvider().configure();
Validation.getBuilder().build();
=>
ValidatorFactory factory = Validation.getDefaultValidatorFactory();
//use generic provider with specific resolver strategy
ValidatorFactoryBuilder<?> factoryBuilder =
Validation.defineBootstrapState()
.providerResolver(...) //optional step
.getBuilder();
=>
Configuration<?> configuration =
Validation.byDefaultProvider()
.providerResolver(...) //optional step
.configure();
//use a specific provider with specific resolver strategy
ValidatorFactoryBuilder<?> factoryBuilder =
Validation.builderType(ACMEValidatorFactoryBuilder.class)
.providerResolver(...) //optional step
.getBuilder();
=>
Configuration<?> configuration =
Validation.byProvider(ACMEValidatorConfiguration.class)
.providerResolver(...) //optional step
.configure();
I am also wondering if we should rename the methods on the Configuration object (former ValidatorFactoryBuilder):
- messageResolver => useMessageResolver
- providerResolver => useProviderResolver
- traversableResolver => useTraversableResolver
- customConfiguration => useCustomConfiguration
- constraintFactory => useConstraintFactory
This makes them a bit more "fluent" but also more verbose.
To Build a Validator
rename ValidatorFactory.defineValidatorState() to ValidatorFactory.usingContext()
rename ValidatorBuilder to ValidatorContext
Here are various bootstraps with the old naming followed by the new naming. We gain consistency with the VF creation as well
Code:
//simple validator creation
Validator validator = validatorFactory.getValidator();
=>
Validator validator = validatorFactory.getValidator(); //unchanged
//with overriding context
Validator validator =
validatorFactory.defineValidatorState()
.traversableResolver(...)
.messageResolver(...)
.getValidator();
=>
Validator validator =
validatorFactory.usingContext()
.traversableResolver(...)
.messageResolver(...)
.getValidator();
What do you think?
There are three layers of changes:
- having a consistent naming between VF and V creations and using more meaningful name for the build method (ie getValidator / getValidatorFactory
- having a consistent path and naming wether you use the default provider or a specific one
- rename the builder classes with meaningful definitions