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("anyemail@yopmail.com");
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");
});
}
Затем проверьте, что после завершения BasicInfo
следует оценить ограничение AdvanceInfo :
@Test
public void whenBasicAndAdvanceInfoIsComplete_thenShouldNotGiveConstraintViolationsWithCompleteInfoValidationGroup() {
RegistrationForm form = buildRegistrationFormWithBasicAndAdvanceInfo();
Set<ConstraintViolation<RegistrationForm>> violations = validator.validate(form, CompleteInfo.class);
assertThat(violations.size()).isEqualTo(0);
}
5. Вывод
В этом кратком руководстве мы увидели, как группировать ограничения javax.validation
.
Как обычно, все фрагменты кода доступны на GitHub .