Вот общее правило большого пальца, которому я следую:
При использовании проверки бина укажите
правила, которые не требуют зависимостей
на других бобах. В тот момент, когда вы зависите
на другом бобе, получите свой сервис
слой для обработки этой зависимости.
Другими словами, если у вас есть ссылка на бин внутри другого, избегайте вставлять это ограничение @NotNull. Для этого лучше всего использовать сервисный уровень, поскольку вы обнаруживаете нарушение намного раньше и в более логичном месте (поскольку другие проверки бизнеса предполагают, что компоненты доступны).
В качестве примера рассмотрим следующую сущность (извинения за нее не будут компилироваться)
@Entity
public class User
{
@Id
private int id;
@NotNull
private String fullName;
@NotNull
private String email;
private Set<Role> roles; //No bean validation constraints here.
...
public boolean mapRoleToUser(Role role)
{ //Validation is done here. Including checks for a null role.
}
}
@Entity
public class Role
{
@Id
private int id;
@NotNull
private String name;
}
Сервисный уровень в этом случае должен проверять, есть ли у пользователя роль или нет. Проверка на этапе pre-persist или pre-update слишком поздняя, особенно когда существует отдельный сервисный уровень с бизнес-логикой и остальной бизнес-логикой в доменной модели (к сожалению, я не видел достаточно хорошее приложение со всей логикой только в модели предметной области).