Repository navigation
Validator Lifecycle
The assertions which run validation — assertThatBean, assertThatProperty, assertThatConstructor — extend
AbstractValidationAssert, which holds exactly three things: the groups, and either a Validator or a
ValidatorFactory supplied by the caller. Assertions on results (violations, paths, descriptors) never touch a
validator and have no such configuration.
| Configured | What each validating call does | Who owns it | Closed by this library |
|---|---|---|---|
usingValidator(Validator) |
uses that validator as is | the caller | — (a validator has no close()) |
usingValidatorFactory(ValidatorFactory) |
takes one Validator from the factory with getValidator()
|
the caller | never |
| neither | builds a factory with Validation.buildDefaultValidatorFactory(), takes a validator, and closes the factory before returning |
the assertion | yes, per call |
In no case is a resource kept past the call.
// caller-owned factory: one bootstrap for many assertions
try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
assertThatBean(user).usingValidatorFactory(factory).isValid();
assertThatBean(other).usingValidatorFactory(factory).isNotValid();
} // the caller closes it, here
// caller-owned validator, used while its factory is open
try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
final Validator validator = factory.getValidator();
assertThatBean(user).usingValidator(validator).isValid();
}-
usingValidatorFactory— the assertion never callsclose()on the factory. The tests wrap a factory in a proxy whoseclose()fails the test, to pin this. -
usingValidator— aValidatorbelongs to the factory that produced it, and the specification forbids using it after that factory is closed. The assertion does not and cannot check this; keeping the factory open for as long as the validator is in use is the caller's job. Hibernate Validator does not reject a validator from a closed factory, so this mistake passes silently with the tested provider. -
neither — the factory exists only for the duration of one validating call. Building it costs a classpath scan
plus a
META-INF/validation.xmlparse, once per assertion method called. A suite which minds that supplies its own factory or validator.
Why usingValidator exists alongside usingValidatorFactory: a factory yields a validator, but a validator cannot
yield its factory. A validator customized through ValidatorFactory.usingContext(), one injected by a framework, or a
test double has no factory to hand over:
// fixed: a MessageInterpolator whose interpolate(…) methods return "customized"
try (ValidatorFactory factory = Validation.buildDefaultValidatorFactory()) {
final Validator validator = factory.usingContext().messageInterpolator(fixed).getValidator();
assertThatBean(new User(null, 0)).usingValidator(validator).isNotValid(violations ->
assertThat(violations).extracting(ConstraintViolation::getMessage).containsOnly("customized"));
}-
usingValidatorandusingValidatorFactoryare alternatives: each clears the other, and the last call wins. -
nullfor either clears it, falling back to the per-call default factory. - With a factory,
getValidator()is called once per validating call, not at configuration time: configuring takes nothing, and twoisValid()calls take two validators. - All three methods, and
targetingGroups, arefinaland return the assertion for chaining. The configuration stays on the assertion object across later calls.
In the default case the factory is closed before the validating method returns, and the consumer of a consumer overload runs after that. So the violation set a consumer receives — and the paths, descriptors and beans reachable from it — were produced by a factory that is already closed by the time the consumer sees them. If a test depends on those objects remaining usable, supply a factory and keep it open.
There is no form that takes a Supplier<ValidatorFactory> and closes what it gets. AssertJ has no hook at the end of
an assertion chain, so such a factory would be scoped to one call rather than one chain, a shared factory passed
through a supplier would be closed by the first call, and closing would invalidate results already handed out. This
is recorded as deliberately not done in the repository's _TODO.md.
assertj-validation · Apache License 2.0 · io.github.jinahya:assertj-validation · Jakarta Validation 3.0 / 3.1 · AssertJ 3.27+ · Java 17+
Running validation
Inspecting results
Reference
External