Difference Between @NotNull, @NotEmpty, and @NotBlank Constraints in Bean Validation – Bean验证中@NotNull、@NotEmpty和@NotBlank约束之间的区别

最后修改: 2018年 10月 11日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

Bean Validation is 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 Validation 是一种标准的验证规范,它允许我们通过使用以注解形式声明的一组约束来轻松验证领域对象

While overall the use of bean validation implementations, such as Hibernate Validator, are fairly straightforward, it’s worth exploring some subtle, yet relevant, differences regarding how some of these constraints are implemented.

虽然总体而言,使用Bean验证实现,例如Hibernate Validator,是相当直接的,但关于如何实现其中的一些约束,值得探索一些微妙的、但相关的差异。

In this tutorial, we’ll explore the differences between the @NotNull, @NotEmpty, and @NotBlank constraints.

在本教程中,我们将探讨@NotNull@NotEmpty,@NotBlank约束之间的区别

2. The Maven Dependencies

2.Maven的依赖性

To quickly set up a working environment and test the behavior of the @NotNull, @NotEmpty, and @NotBlank constraints, first we need to add the required Maven dependencies.

为了快速建立工作环境并测试@NotNull@NotEmpty@NotBlank约束的行为,首先我们需要添加必要的Maven依赖。

In this case, we’ll use Hibernate Validator, the bean validation reference implementation, for validating our domain objects.

在这种情况下,我们将使用Hibernate Validator,bean验证参考实现,来验证我们的域对象。

Here’s the relevant section of our pom.xml file:

下面是我们的pom.xml文件的相关部分。

<dependencies> 
    <dependency> 
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-validator</artifactId>
        <version>6.0.13.Final</version>
    </dependency> 
    <dependency> 
        <groupId>org.glassfish</groupId>
        <artifactId>javax.el</artifactId>
        <version>3.0.0</version>
     </dependency>
</dependencies>

We’ll use JUnit and AssertJ in our unit tests, so make sure to check the latest versions of hibernate-validator, GlassFish’s EL implementation, junit, and assertj-core on Maven Central.

我们将在单元测试中使用JUnitAssertJ,因此请确保检查hibernate-validator, GlassFish的EL实现junit,以及Maven中心的assertj-core

3. The @NotNull Constraint

3.@NotNull约束

Moving forward, let’s implement a naive UserNotNull domain class and constrain its name field with the @NotNull annotation:

继续前进,让我们实现一个天真的UserNotNull域类,并@NotNull注解约束name字段。

public class UserNotNull {
    
    @NotNull(message = "Name may not be null")
    private String name;
    
    // standard constructors / getters / toString   
}

Now we need to examine how @NotNull actually works under the hood

现在我们需要检查一下@NotNull实际上是如何在引擎盖下工作的

To do so, let’s create a simple unit test for the class, and validate a few instances of it:

为此,让我们为该类创建一个简单的单元测试,并验证它的几个实例。

@BeforeClass
public static void setupValidatorInstance() {
    validator = Validation.buildDefaultValidatorFactory().getValidator();
}

@Test
public void whenNotNullName_thenNoConstraintViolations() {
    UserNotNull user = new UserNotNull("John");
    Set<ConstraintViolation<UserNotNull>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(0);
}
    
@Test
public void whenNullName_thenOneConstraintViolation() {
    UserNotNull user = new UserNotNull(null);
    Set<ConstraintViolation<UserNotNull>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(1);
}
    
@Test
public void whenEmptyName_thenNoConstraintViolations() {
    UserNotNull user = new UserNotNull("");
    Set<ConstraintViolation<UserNotNull>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(0);
}

As expected, the @NotNull constraint won’t allow null values for the constrained field(s). However, the field(s) can be empty.

正如预期的那样,@NotNull约束不允许受约束字段为空值。然而,字段可以是空的。

To better understand this, let’s look at the NotNullValidator classisValid() method, which the @NotNull constraint uses. The method implementation is really trivial:

为了更好地理解这一点,让我们看看NotNullValidatorisValid()方法,@NotNull约束使用该方法。该方法的实现其实很微不足道。

public boolean isValid(Object object) {
    return object != null;  
}

As shown above, a field (e.g. CharSequence, Collection, Map, or Array) constrained with @NotNull must be not null. An empty value, however, is perfectly legal.

如上所示,一个字段(例如CharSequenceCollectionMap,Array)@NotNull约束,必须是不为空。然而,一个空值是完全合法的

4. The @NotEmpty Constraint

4.@NotEmpty约束

Now let’s implement a sample UserNotEmpty class and use the @NotEmpty constraint:

现在让我们实现一个示例UserNotEmpty类并使用@NotEmpty约束条件。

public class UserNotEmpty {
    
    @NotEmpty(message = "Name may not be empty")
    private String name;
    
    // standard constructors / getters / toString
}

With the class in place, let’s test it by assigning different values to the name field:

有了这个类,让我们通过给name字段分配不同的值来测试它。

@Test
public void whenNotEmptyName_thenNoConstraintViolations() {
    UserNotEmpty user = new UserNotEmpty("John");
    Set<ConstraintViolation<UserNotEmpty>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(0);
}
    
@Test
public void whenEmptyName_thenOneConstraintViolation() {
    UserNotEmpty user = new UserNotEmpty("");
    Set<ConstraintViolation<UserNotEmpty>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(1);
}
    
@Test
public void whenNullName_thenOneConstraintViolation() {
    UserNotEmpty user = new UserNotEmpty(null);
    Set<ConstraintViolation<UserNotEmpty>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(1);
}

The @NotEmpty annotation makes use of the @NotNull class’ isValid() implementation, and also checks that the size/length of the supplied object (of course, this varies according to the type of object being validated) is greater than zero.

@NotEmpty注解利用了@NotNull类的isValid()实现,并且还检查提供的对象的大小/长度(当然,这根据被验证对象的类型而不同)是否大于零。

In a nutshell, 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.

简而言之,这意味着一个字段(例如CharSequenceCollectionMap,Array)受到@NotEmpty的约束,必须不是空的,并且其大小/长度必须大于零

Additionally, we can be even more restrictive if we use the @NotEmpty annotation in conjunction with @Size.

此外,如果我们将@NotEmpty注解与@Size.结合使用,我们可以有更多限制。

In doing so, we’d also enforce that the object’s min and max size values are within the specified min/max range:

这样做的时候,我们也会强制要求对象的最小和最大尺寸值在指定的最小/最大范围内。

@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. The @NotBlank Constraint

5.@NotBlank约束

Similarly, we can constrain a class field with the @NotBlank annotation:

同样地,我们可以用@NotBlank注解来约束一个类字段。

public class UserNotBlank {

    @NotBlank(message = "Name may not be blank")
    private String name;
    
    // standard constructors / getters / toString

}

Along the same lines, we can implement a unit test to understand how the @NotBlank constraint works:

按照同样的思路,我们可以实现一个单元测试,以了解@NotBlank约束如何工作。

@Test
public void whenNotBlankName_thenNoConstraintViolations() {
    UserNotBlank user = new UserNotBlank("John");
    Set<ConstraintViolation<UserNotBlank>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(0);
}
    
@Test
public void whenBlankName_thenOneConstraintViolation() {
    UserNotBlank user = new UserNotBlank(" ");
    Set<ConstraintViolation<UserNotBlank>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(1);
}
    
@Test
public void whenEmptyName_thenOneConstraintViolation() {
    UserNotBlank user = new UserNotBlank("");
    Set<ConstraintViolation<UserNotBlank>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(1);
}
    
@Test
public void whenNullName_thenOneConstraintViolation() {
    UserNotBlank user = new UserNotBlank(null);
    Set<ConstraintViolation<UserNotBlank>> violations = validator.validate(user);
 
    assertThat(violations.size()).isEqualTo(1);
}

The @NotBlank annotation uses the NotBlankValidator class, which checks that a character sequence’s trimmed length is not empty:

@NotBlank注解使用NotBlankValidator类,它检查一个字符序列的修剪长度是否为空。

public boolean isValid(
  CharSequence charSequence, 
  ConstraintValidatorContext constraintValidatorContext)
    if (charSequence == null ) {
        return true; 
    } 
    return charSequence.toString().trim().length() > 0;
}

Funny enough, the method returns true for null values. So we might think that @NotBlank does allow null values, but it actually doesn’t.

有趣的是,该方法对空值返回真。所以我们可能认为@NotBlank确实允许空值,但实际上它不允许。

The @NotNull class’ isValid() method is called after the @NotBlank class’ isValid(), hence forbidding null values.

@NotNull类的isValid()方法在@NotBlank类的isValid()之后被调用,因此禁止了空值。

To put it simply, a String field constrained with @NotBlank must be not null, and the trimmed length must be greater than zero.

简单地说,@NotBlank约束的字符串字段必须不是空的,并且修剪的长度必须大于0

6. A Side-by-Side Comparison

6.并排的比较

So far, we’ve taken an in-depth look at how the @NotNull, @NotEmpty, and @NotBlank constraints operate individually on class fields.

到目前为止,我们已经深入研究了@NotNull@NotEmpty@NotBlank约束如何在类域上单独操作。

Let’s perform a quick side-by-side comparison, so we can have a bird’s eye view of the constraints’ functionality and easily spot their differences:

让我们进行一次快速的并排比较,这样我们就可以对约束条件的功能有一个鸟瞰,并容易发现它们的差异。

  • @NotNull: a constrained CharSequence, Collection, Map, or Array is valid as long as it’s not null, but it can be empty.
  • @NotEmpty: a constrained CharSequence, Collection, Map, or Array is valid as long as it’s not null, and its size/length is greater than zero.
  • @NotBlank: a constrained String is valid as long as it’s not null, and the trimmed length is greater than zero.

7. Conclusion

7.结论

In this article, we looked at the @NotNull, @NotEmpty, and @NotBlank constraints implemented in Bean Validation, and highlighted their similarities and differences.

在这篇文章中,我们看了Bean Validation中实现的@NotNull@NotEmpty@NotBlank约束,并强调了它们的相似性和差异。

As usual, all the code samples shown in this article are available over on GitHub.

像往常一样,本文中显示的所有代码样本都可以在GitHub上找到