«1. Введение
В нашем учебнике по основам проверки Java Bean мы видели использование различных встроенных ограничений javax.validation. В этом руководстве мы увидим, как группировать ограничения javax.validation.
2. Пример использования
Существует много сценариев, в которых нам нужно применить ограничения к определенному набору полей компонента, а затем мы хотим применить ограничения к другому набору полей того же компонента.
Например, давайте представим, что у нас есть двухэтапная форма регистрации. На первом этапе мы просим пользователя предоставить основную информацию, такую как имя, фамилия, идентификатор электронной почты, номер телефона и капча. Когда пользователь отправляет эти данные, мы хотим проверить только эту информацию.
На следующем этапе мы просим пользователя предоставить некоторую другую информацию, например адрес, и мы также хотим проверить эту информацию — обратите внимание, что капча присутствует на обоих этапах.
3. Группирование ограничений проверки
Все ограничения проверки javax имеют атрибут с именем groups. Когда мы добавляем ограничение к элементу, мы можем объявить имя группы, к которой принадлежит ограничение. Это делается путем указания имени класса группового интерфейса в атрибутах групп ограничения.
Лучший способ что-то понять — запачкать руки. Давайте посмотрим в действии, как мы объединяем ограничения javax в группы.
3.1. Объявление групп ограничений
Первым шагом является создание некоторых интерфейсов. Эти интерфейсы будут именами групп ограничений. В нашем случае использования мы разделяем ограничения проверки на две группы.
Давайте посмотрим на первую группу ограничений, BasicInfo:
public interface BasicInfo {
}
Следующая группа ограничений, AdvanceInfo:
public interface AdvanceInfo {
}
3.2. Использование групп ограничений
Теперь, когда мы объявили наши группы ограничений, пришло время использовать их в нашем Java-бине RegistrationForm:
public class RegistrationForm {
@NotBlank(groups = BasicInfo.class)
private String firstName;
@NotBlank(groups = BasicInfo.class)
private String lastName;
@Email(groups = BasicInfo.class)
private String email;
@NotBlank(groups = BasicInfo.class)
private String phone;
@NotBlank(groups = {BasicInfo.class, AdvanceInfo.class})
private String captcha;
@NotBlank(groups = AdvanceInfo.class)
private String street;
@NotBlank(groups = AdvanceInfo.class)
private String houseNumber;
@NotBlank(groups = AdvanceInfo.class)
private String zipCode;
@NotBlank(groups = AdvanceInfo.class)
private String city;
@NotBlank(groups = AdvanceInfo.class)
private String contry;
}
С помощью атрибута групп ограничений мы разделили поля нашего компонента на две группы. в соответствии с нашим вариантом использования. По умолчанию все ограничения включены в группу ограничений по умолчанию.
3.3. Тестирование ограничений с одной группой
Теперь, когда мы объявили группы ограничений и использовали их в нашем классе компонентов, пришло время увидеть эти группы ограничений в действии.
Во-первых, мы увидим, когда основная информация не будет полной, используя нашу группу ограничений BasicInfo для проверки. Мы должны получить нарушение ограничения для любого поля, оставленного пустым, где мы использовали BasicInfo.class в атрибуте groups ограничения поля @NotBlank:
public class RegistrationFormUnitTest {
private static Validator validator;
@BeforeClass
public static void setupValidatorInstance() {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
@Test
public void whenBasicInfoIsNotComplete_thenShouldGiveConstraintViolationsOnlyForBasicInfo() {
RegistrationForm form = buildRegistrationFormWithBasicInfo();
form.setFirstName("");
Set<ConstraintViolation<RegistrationForm>> violations = validator.validate(form, BasicInfo.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getMessage()).isEqualTo("must not be blank");
assertThat(action.getPropertyPath().toString()).isEqualTo("firstName");
});
}
private RegistrationForm buildRegistrationFormWithBasicInfo() {
RegistrationForm form = new RegistrationForm();
form.setFirstName("devender");
form.setLastName("kumar");
form.setEmail("[email protected]");
form.setPhone("12345");
form.setCaptcha("Y2HAhU5T");
return form;
}
//... additional tests
}
В следующем сценарии мы проверим, когда расширенная информация неполна, используя нашу группу ограничений AdvanceInfo для проверки:
@Test
public void whenAdvanceInfoIsNotComplete_thenShouldGiveConstraintViolationsOnlyForAdvanceInfo() {
RegistrationForm form = buildRegistrationFormWithAdvanceInfo();
form.setZipCode("");
Set<ConstraintViolation<RegistrationForm>> violations = validator.validate(form, AdvanceInfo.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getMessage()).isEqualTo("must not be blank");
assertThat(action.getPropertyPath().toString()).isEqualTo("zipCode");
});
}
private RegistrationForm buildRegistrationFormWithAdvanceInfo() {
RegistrationForm form = new RegistrationForm();
return populateAdvanceInfo(form);
}
private RegistrationForm populateAdvanceInfo(RegistrationForm form) {
form.setCity("Berlin");
form.setContry("DE");
form.setStreet("alexa str.");
form.setZipCode("19923");
form.setHouseNumber("2a");
form.setCaptcha("Y2HAhU5T");
return form;
}
3.4. Тестирование ограничений, имеющих несколько групп
Мы можем указать несколько групп для ограничения. В нашем случае мы используем капчу как в базовой, так и в расширенной информации. Давайте сначала проверим капчу с помощью BasicInfo:
@Test
public void whenCaptchaIsBlank_thenShouldGiveConstraintViolationsForBasicInfo() {
RegistrationForm form = buildRegistrationFormWithBasicInfo();
form.setCaptcha("");
Set<ConstraintViolation<RegistrationForm>> violations = validator.validate(form, BasicInfo.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getMessage()).isEqualTo("must not be blank");
assertThat(action.getPropertyPath().toString()).isEqualTo("captcha");
});
}
Теперь давайте проверим капчу с помощью AdvanceInfo:
@Test
public void whenCaptchaIsBlank_thenShouldGiveConstraintViolationsForAdvanceInfo() {
RegistrationForm form = buildRegistrationFormWithAdvanceInfo();
form.setCaptcha("");
Set<ConstraintViolation<RegistrationForm>> violations = validator.validate(form, AdvanceInfo.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getMessage()).isEqualTo("must not be blank");
assertThat(action.getPropertyPath().toString()).isEqualTo("captcha");
});
}
4. Указание порядка проверки группы ограничений с помощью GroupSequence
По умолчанию группы ограничений не оцениваются в какой-либо конкретный заказ. Но у нас могут быть случаи использования, когда некоторые группы должны быть проверены раньше других. Для этого мы можем указать порядок групповой проверки с помощью GroupSequence.
Существует два способа использования аннотации GroupSequence:
-
на объекте, проверяемом на интерфейсе
4.1. Использование GroupSequence для проверяемой сущности
Это простой способ упорядочить ограничения. Давайте аннотируем сущность с помощью GroupSequence и укажем порядок ограничений:
@GroupSequence({BasicInfo.class, AdvanceInfo.class})
public class RegistrationForm {
@NotBlank(groups = BasicInfo.class)
private String firstName;
@NotBlank(groups = AdvanceInfo.class)
private String street;
}
4.2. Использование GroupSequence на интерфейсе
Мы также можем указать порядок проверки ограничений с помощью интерфейса. Преимущество этого подхода в том, что ту же последовательность можно использовать для других сущностей. Давайте посмотрим, как мы можем использовать GroupSequence с интерфейсами, которые мы определили выше:
@GroupSequence({BasicInfo.class, AdvanceInfo.class})
public interface CompleteInfo {
}
4.3. Тестирование GroupSequence
Теперь давайте проверим GroupSequence. Во-первых, мы проверим, что если BasicInfo неполная, то групповое ограничение AdvanceInfo не будет оцениваться:
@Test
public void whenBasicInfoIsNotComplete_thenShouldGiveConstraintViolationsForBasicInfoOnly() {
RegistrationForm form = buildRegistrationFormWithBasicInfo();
form.setFirstName("");
Set<ConstraintViolation<RegistrationForm>> violations = validator.validate(form, CompleteInfo.class);
assertThat(violations.size()).isEqualTo(1);
violations.forEach(action -> {
assertThat(action.getMessage()).isEqualTo("must not be blank");
assertThat(action.getPropertyPath().toString()).isEqualTo("firstName");
});
}
«
@Test
public void whenBasicAndAdvanceInfoIsComplete_thenShouldNotGiveConstraintViolationsWithCompleteInfoValidationGroup() {
RegistrationForm form = buildRegistrationFormWithBasicAndAdvanceInfo();
Set<ConstraintViolation<RegistrationForm>> violations = validator.validate(form, CompleteInfo.class);
assertThat(violations.size()).isEqualTo(0);
}
«Затем проверьте, что после завершения BasicInfo следует оценить ограничение AdvanceInfo:
5. Заключение
В этом кратком руководстве мы увидели, как группировать ограничения javax.validation.