Перейти к основному содержимому

Группировка ограничений проверки Javax

· 5 мин. чтения

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 .