public record Schema(
@Null(groups = { NotManaged.class })
@NotNull(groups = { Managed.class })
Long id,
@NotNull
String externalId,
@NotNull
String name,
@Null(groups = { NotManaged.class })
@NotNull(groups = { Managed.class })
LocalDateTime creationDate,
@Null(groups = { NotManaged.class })
@NotNull(groups = { Managed.class })
LocalDateTime lastUpdated
) {
// . . .
}
Validation groups
jakarta.validation.groups allow us to configure the constraints to be validated depending on the context.
For example, in some situations may have sense only to validate certain constraints when a domain entity is being created (not managed)
and not when is updated (managed), the ID and creation / update timestamps for example.
In that case we can define the constraints that will be executed in each case using different groups
In this example, the ID and creation / updated timestamps attributes will be forced to be null only when the object
is not managed by the application. Any constraint not assigned explicitly to any group will be assigned to the default group.
Custom validation groups can be defined as interfaces as following:
public final class CommonValidationGroups {
private CommonValidationGroups() { }
public interface NotManaged { }
public interface Managed { }
}
Then, when we configure a validation for an object, using the Validator object directly or
using Spring’s @Validated annotation, we can specify one or more validation groups to be evaluated.
import jakarta.validation.groups.Default;
@Validated({ Default.class, NotManaged.class })
public Schema createSchema(@Valid Schema schema) {
// . . .
}
@Validated({ Default.class, Managed.class })
public Schema updateSchema(@Valid Schema schema) {
// . . .
}
import jakarta.validation.groups.Default;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
// . . .
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final Schema schema = // . . .
Set<ConstraintViolation<Schema>> constraintViolations = validator.validate(providedStore, Default.class, CommonValidationGroups.Managed.class);
We have to specify the jakarta.validation.groups.Default so the validations not assigned explicitly to
any group are executed (E.G. the @NotNull constraint on externalId and name fields).
We can also extend from jakarta.validation.groups.Default to automatically apply default groups constraints
when we execute the validation only specifying our custom validation groups, although doing this we will lose the
possibility to individually evaluate these custom groups, as always will also evaluate default group constraints.
import jakarta.validation.groups.Default;
public final class CommonValidationGroups {
private CommonValidationGroups() { }
public interface NotManaged extends Default { }
public interface Managed extends Default { }
}
import jakarta.validation.groups.Default;
@Validated({ NotManaged.class })
public Schema createSchema(@Valid Schema schema) {
// . . .
}
@Validated({ Managed.class })
public Schema updateSchema(@Valid Schema schema) {
// . . .
}
import jakarta.validation.groups.Default;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
// . . .
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final Schema schema = // . . .
Set<ConstraintViolation<Schema>> constraintViolations = validator.validate(providedStore, CommonValidationGroups.Managed.class);
Note that in that case, if we specify only the jakarta.validation.groups.Default group (or any group) in the validator,
we will only evaluate default groups related constraint although our custom validation groups extends from the default group.
import jakarta.validation.groups.Default;
import jakarta.validation.ConstraintViolation;
import jakarta.validation.Validation;
import jakarta.validation.Validator;
// . . .
final Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
final Schema schema = // . . .
Set<ConstraintViolation<Schema>> constraintViolations = validator.validate(providedStore);
/* Managed / NotManaged groups constraints will not be evaluated, although they extend the default group
* as none of them are specified in the `validate` statement
*/