Diferença entre as restrições @NotNull, @NotEmpty e @NotBlank na validação de bean
1. Visão geral
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.
Embora no geral, o uso de implementações de validação de bean, comoHibernate Validator seja bastante simples, vale a pena explorar algumas diferenças sutis - ainda que relevantes - sobre como algumas dessas restrições são implementadas.
Neste tutorial,we’ll spot the differences between the @NotNull, @NotEmpty, and @NotBlank constraints.
2. As dependências do Maven
Para configurar rapidamente um ambiente de trabalho e testar o comportamento das restrições@NotNull,@NotEmpty e@NotBlank, primeiro precisamos adicionar as dependências Maven necessárias.
Neste caso, usaremosHibernate Validator, a implementação de referência de validação de bean, para validar nossos objetos de domínio.
Esta é a seção relevante de nosso arquivopom.xml:
org.hibernate
hibernate-validator
6.0.13.Final
org.glassfish
javax.el
3.0.0
UsaremosJUniteAssertJ em nossos testes de unidade, portanto, certifique-se de verificar as versões mais recentes dehibernate-validator,GlassFish’s EL implementation,junit eassertj-core no Maven Central.
3. A restrição@NotNull
Seguindo em frente, vamos implementar uma classe de domínioUserNotNull ingênua econstrain seu camponame com a anotação@NotNull:
public class UserNotNull {
@NotNull(message = "Name may not be null")
private String name;
// standard constructors / getters / toString
}
Agora, precisamos ver como@NotNull realmente funciona nos bastidores.
Para fazer isso, vamos criar um teste de unidade simples para a classe e validar algumas instâncias dele:
@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);
}
Como esperado, a restrição@NotNull não permitirá valores nulos para o (s) campo (s) restrito (s). Mesmo assim, os campos podem estar vazios.
Para entender melhor isso, vamos dar uma olhada no métodoNotNullValidator class ‘isValid(), que a restrição@NotNull usa. A implementação do método é realmente trivial:
public boolean isValid(Object object) {
return object != null;
}
Como mostrado acima,a field (e.g. CharSequence, Collection, Map, or Array) constrained with @NotNull must be not null. An empty value, however, is perfectly legal.
4. A restrição@NotEmpty
Agora, vamos implementar uma classe de amostraUserNotEmpty e usar a restrição@NotEmpty:
public class UserNotEmpty {
@NotEmpty(message = "Name may not be empty")
private String name;
// standard constructors / getters / toString
}
Com a classe estabelecida, vamos apenas testá-la atribuindo valores diferentes ao camponame:
@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);
}
A anotação@NotEmpty faz uso da implementaçãoisValid() da classe@NotNull e, adicionalmente, verifica se o tamanho / comprimento do objeto fornecido (claro, isso varia de acordo com o tipo de objeto que está sendo validado ) é maior que zero.
Resumindo,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.
Além disso, podemos ser ainda mais restritivos se usarmos a anotação@NotEmpty em conjunto com@Size.
Ao fazer isso, também impomos que os valores de tamanho mínimo e máximo do objeto estejam dentro do intervalo mínimo / máximo especificado:
@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. A restrição@NotBlank
Da mesma forma, podemos restringir um campo de classe com a anotação@NotBlank:
public class UserNotBlank {
@NotBlank(message = "Name may not be blank")
private String name;
// standard constructors / getters / toString
}
Na mesma linha, podemos implementar um teste de unidade para entender como funciona a restrição@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);
}
A anotação@NotBlank usa a classeNotBlankValidator, que verifica se o comprimento aparado de uma sequência de caracteres não está vazio:
public boolean isValid(
CharSequence charSequence,
ConstraintValidatorContext constraintValidatorContext)
if (charSequence == null ) {
return true;
}
return charSequence.toString().trim().length() > 0;
}
Engraçado o suficiente, o método retorna true para valores nulos. Então, podemos pensar que@NotBlank permite valores nulos, mas na verdade não permite.
O método isValid () da classe@NotNull é chamado após isValid () da classe@NotBlank, portanto, proibindo valores nulos.
Simplificando,a String field constrained with @NotBlank must be not null and the trimmed length must be greater than zero.
6. Uma comparação lado a lado
Até agora, demos uma olhada em profundidade em como as restrições@NotNull,@NotEmpty e@NotBlank operam individualmente nos campos de classe.
Vamos fazer uma rápida comparação lado a lado, para que possamos ter uma visão geral da funcionalidade das restrições e identificar facilmente suas diferenças:
-
@NotNull: umCharSequence restrito,Collection,Map, ouArray é válido desde que não seja nulo, mas pode estar vazio
-
@NotEmpty: umCharSequence restrito,Collection,Map, ouArray é válido, contanto que não seja nulo e seu tamanho / comprimento seja maior que zero
-
@NotBlank: umString restrito é válido, desde que não seja nulo e o comprimento aparado seja maior que zero
7. Conclusão
Neste artigo, examinamos as restriçõesNotNull,@NotEmpty e@NotBlank implementadas na Validação de Bean e destacamos suas semelhanças e diferenças.
Como de costume, todos os exemplos de código mostrados neste artigo estão disponíveisover on GitHub.