Разница между ограничениями @NotNull, @NotEmpty и @NotBlank при проверке бинов
1. обзор
Bean Validationis a standard validation specification that allows us to easily validate domain objects by using a set of constraints declared in the form of annotations.
Хотя в целом использование реализаций проверки bean-компонентов, таких какHibernate Validator, довольно просто, стоит изучить некоторые тонкие, но актуальные различия, касающиеся того, как реализуются некоторые из этих ограничений.
В этом руководствеwe’ll spot the differences between the @NotNull, @NotEmpty, and @NotBlank constraints.
2. Зависимости Maven
Чтобы быстро настроить рабочую среду и протестировать поведение ограничений@NotNull,@NotEmpty и@NotBlank, сначала нам нужно добавить необходимые зависимости Maven.
В этом случае мы будем использоватьHibernate Validator, эталонную реализацию проверки bean-компонента, для проверки наших объектов домена.
Вот соответствующий раздел нашего файлаpom.xml:
org.hibernate
hibernate-validator
6.0.13.Final
org.glassfish
javax.el
3.0.0
Мы будем использоватьJUnit иAssertJ в наших модульных тестах, поэтому обязательно проверьте последние версииhibernate-validator,GlassFish’s EL implementation,junit иassertj-coreна Maven Central.
3. Ограничение@NotNull
Двигаясь вперед, давайте реализуем наивный класс доменаUserNotNull иconstrain его полеname с аннотацией@NotNull:
public class UserNotNull {
@NotNull(message = "Name may not be null")
private String name;
// standard constructors / getters / toString
}
Теперь нам нужно увидеть, как@NotNull на самом деле работает под капотом.
Для этого давайте создадим простой модульный тест для класса и проверим несколько его экземпляров:
@BeforeClass
public static void setupValidatorInstance() {
validator = Validation.buildDefaultValidatorFactory().getValidator();
}
@Test
public void whenNotNullName_thenNoConstraintViolations() {
UserNotNull user = new UserNotNull("John");
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(0);
}
@Test
public void whenNullName_thenOneConstraintViolation() {
UserNotNull user = new UserNotNull(null);
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(1);
}
@Test
public void whenEmptyName_thenNoConstraintViolations() {
UserNotNull user = new UserNotNull("");
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(0);
}
Как и ожидалось, ограничение@NotNull не допускает нулевых значений для ограниченного поля (полей). Тем не менее, поле (я) может быть пустым.
Чтобы лучше понять это, давайте посмотрим на методNotNullValidator class ‘isValid(), который используется ограничением@NotNull. Реализация метода действительно тривиальна:
public boolean isValid(Object object) {
return object != null;
}
Как показано выше,a field (e.g. CharSequence, Collection, Map, or Array) constrained with @NotNull must be not null. An empty value, however, is perfectly legal.
4. Ограничение@NotEmpty
Теперь давайте реализуем образец классаUserNotEmpty и воспользуемся ограничением@NotEmpty:
public class UserNotEmpty {
@NotEmpty(message = "Name may not be empty")
private String name;
// standard constructors / getters / toString
}
Имея класс на месте, давайте просто протестируем его, присвоив различные значения полюname:
@Test
public void whenNotEmptyName_thenNoConstraintViolations() {
UserNotEmpty user = new UserNotEmpty("John");
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(0);
}
@Test
public void whenEmptyName_thenOneConstraintViolation() {
UserNotEmpty user = new UserNotEmpty("");
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(1);
}
@Test
public void whenNullName_thenOneConstraintViolation() {
UserNotEmpty user = new UserNotEmpty(null);
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(1);
}
Аннотация@NotEmpty использует реализацию класса@NotNull 'isValid() и дополнительно проверяет, что размер / длина предоставленного объекта (конечно, это зависит от типа проверяемого объекта. ) больше нуля.
Вкратце,this means that a field (e.g. CharSequence, Collection, Map, or Array) constrained with @NotEmpty must be not null and its size/length must be greater than zero.
Кроме того, мы можем быть еще более ограничительными, если будем использовать аннотацию@NotEmpty вместе с@Size.
При этом мы также должны обеспечить, чтобы значения минимального и максимального размера объекта находились в пределах указанного минимального / максимального диапазона:
@NotEmpty(message = "Name may not be empty")
@Size(min = 2, max = 32, message = "Name must be between 2 and 32 characters long")
private String name;
5. Ограничение@NotBlank
Точно так же мы можем ограничить поле класса аннотацией@NotBlank:
public class UserNotBlank {
@NotBlank(message = "Name may not be blank")
private String name;
// standard constructors / getters / toString
}
Аналогичным образом мы можем реализовать модульный тест, чтобы понять, как работает ограничение@NotBlank:
@Test
public void whenNotBlankName_thenNoConstraintViolations() {
UserNotBlank user = new UserNotBlank("John");
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(0);
}
@Test
public void whenBlankName_thenOneConstraintViolation() {
UserNotBlank user = new UserNotBlank(" ");
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(1);
}
@Test
public void whenEmptyName_thenOneConstraintViolation() {
UserNotBlank user = new UserNotBlank("");
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(1);
}
@Test
public void whenNullName_thenOneConstraintViolation() {
UserNotBlank user = new UserNotBlank(null);
Set> violations = validator.validate(user);
assertThat(violations.size()).isEqualTo(1);
}
В аннотации@NotBlank используется классNotBlankValidator, который проверяет, что обрезанная длина последовательности символов не пуста:
public boolean isValid(
CharSequence charSequence,
ConstraintValidatorContext constraintValidatorContext)
if (charSequence == null ) {
return true;
}
return charSequence.toString().trim().length() > 0;
}
Забавно, но метод возвращает true для нулевых значений. Итак, мы можем подумать, что@NotBlank действительно допускает нулевые значения, но на самом деле это не так.
Метод isValid () класса@NotNull вызывается после класса@NotBlank isValid (), что запрещает нулевые значения.
Проще говоря,a String field constrained with @NotBlank must be not null and the trimmed length must be greater than zero.
6. Параллельное сравнение
Пока что мы подробно рассмотрели, как ограничения@NotNull,@NotEmpty и@NotBlank работают индивидуально с полями классов.
Давайте проведем быстрое параллельное сравнение, чтобы мы могли видеть функциональность ограничений с высоты птичьего полета и легко определять их различия:
-
@NotNull: ограниченныйCharSequence,Collection,Map, илиArray действителен, если он не равен нулю, но может быть пустым
-
@NotEmpty: ограниченныйCharSequence,Collection,Map, илиArray действителен, если он не равен нулю и его размер / длина больше нуля
-
@NotBlank: ограниченныйString действителен до тех пор, пока он не равен нулю и обрезанная длина больше нуля
7. Заключение
В этой статье мы рассмотрели ограниченияNotNull,@NotEmpty и@NotBlank, реализованные в Bean Validation, и подчеркнули их сходства и различия.
Как обычно, доступны все примеры кода, показанные в этой статьеover on GitHub.