Unterschied zwischen @NotNull-, @NotEmpty- und @NotBlank-Einschränkungen bei der Bean-Validierung

Unterschied zwischen @NotNull, @NotEmpty und @NotBlank-Einschränkungen bei der Bean-Validierung

1. Überblick

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.

Insgesamt ist die Verwendung von Bean-Validierungsimplementierungen wieHibernate Validator recht unkompliziert. Es lohnt sich jedoch, einige subtile, jedoch relevante Unterschiede hinsichtlich der Implementierung einiger dieser Einschränkungen zu untersuchen.

In diesem Tutorial werdenwe’ll spot the differences between the @NotNull, @NotEmpty, and @NotBlank constraints.

2. Die Maven-Abhängigkeiten

Um schnell eine Arbeitsumgebung einzurichten und das Verhalten der Einschränkungen@NotNull,@NotEmpty und@NotBlank zu testen, müssen zuerst die erforderlichen Maven-Abhängigkeiten hinzugefügt werden.

In diesem Fall verwenden wirHibernate Validator, die Referenzimplementierung für die Bean-Validierung, zur Validierung unserer Domänenobjekte.

Hier ist der relevante Abschnitt unsererpom.xml-Datei:


    
        org.hibernate
        hibernate-validator
        6.0.13.Final
    
    
        org.glassfish
        javax.el
        3.0.0
     

Wir werdenJUnit undAssertJ in unseren Komponententests verwenden. Überprüfen Sie daher unbedingt die neuesten Versionen vonhibernate-validator,GlassFish’s EL implementation,junit undassertj-core auf Maven Central.

3. Die@NotNull-Einschränkung

In Zukunft implementieren wir eine naiveUserNotNull-Domänenklasse undconstrainname-Feld mit der Annotation@NotNull:

public class UserNotNull {

    @NotNull(message = "Name may not be null")
    private String name;

    // standard constructors / getters / toString
}

Jetzt müssen wir sehen, wie@NotNull tatsächlich unter der Haube funktioniert

Erstellen Sie dazu einen einfachen Komponententest für die Klasse und validieren Sie einige Instanzen davon:

@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);
}

Wie erwartet lässt die Einschränkung von@NotNullkeine Nullwerte für die eingeschränkten Felder zu. Trotzdem können die Felder leer sein.

Um dies besser zu verstehen, schauen wir uns dieNotNullValidator class-MethodeisValid()an, die von der@NotNull-Beschränkung verwendet wird. Die Implementierung der Methode ist wirklich trivial:

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

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

4. Die@NotEmpty-Einschränkung

Implementieren wir nun eine Beispielklasse fürUserNotEmptyund verwenden die Einschränkung für@NotEmpty:

public class UserNotEmpty {

    @NotEmpty(message = "Name may not be empty")
    private String name;

    // standard constructors / getters / toString
}

Wenn die Klasse vorhanden ist, testen wir sie einfach, indem wir dem Feldnameunterschiedliche Werte zuweisen:

@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);
}

Die Annotation@NotEmptyverwendet die Implementierung der@NotNull-KlasseisValid()und prüft zusätzlich, ob die Größe / Länge des bereitgestellten Objekts (dies hängt natürlich vom Typ des zu validierenden Objekts ab) ) ist größer als Null.

Kurz gesagt,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.

Darüber hinaus können wir noch restriktiver sein, wenn wir die Annotation@NotEmpty in Verbindung mit@Size. verwenden

Auf diese Weise möchten wir auch sicherstellen, dass die Min- und Max-Größenwerte des Objekts innerhalb des angegebenen Min / Max-Bereichs liegen:

@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. Die@NotBlank-Einschränkung

In ähnlicher Weise können wir ein Klassenfeld mit der Annotation@NotBlankeinschränken:

public class UserNotBlank {

    @NotBlank(message = "Name may not be blank")
    private String name;

    // standard constructors / getters / toString

}

In diesem Sinne können wir einen Komponententest implementieren, um zu verstehen, wie die Einschränkung von@NotBlankfunktioniert:

@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);
}

Die Annotation@NotBlankverwendet die KlasseNotBlankValidator, die überprüft, ob die zugeschnittene Länge einer Zeichenfolge nicht leer ist:

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

Witzigerweise gibt die Methode true für Nullwerte zurück. Wir könnten also denken, dass@NotBlank Nullwerte zulässt, aber tatsächlich nicht.

Die Methode 'isValid () der Klasse@NotNullwird nach der Klasse' isValid () der@NotBlankaufgerufen, wodurch Nullwerte verboten werden.

Einfach ausgedrückt,a String field constrained with @NotBlank must be not null and the trimmed length must be greater than zero.

6. Ein Side-by-Side-Vergleich

Bisher haben wir uns eingehend mit der Funktionsweise der Einschränkungen von@NotNull,@NotEmpty und@NotBlank für Klassenfelder befasst.

Lassen Sie uns einen schnellen Vergleich nebeneinander durchführen, damit wir die Funktionalität der Einschränkungen aus der Vogelperspektive betrachten und ihre Unterschiede leicht erkennen können:

  • @NotNull: ist ein eingeschränktesCharSequence,Collection,Map, oderArray ist gültig, solange es nicht null ist, aber es kann leer sein

  • @NotEmpty: ist ein eingeschränktesCharSequence,Collection,Map, oderArray ist gültig, solange es nicht null ist und seine Größe / Länge größer als null ist

  • @NotBlank: ein eingeschränktesString ist gültig, solange es nicht null ist und die zugeschnittene Länge größer als Null ist

7. Fazit

In diesem Artikel haben wir uns die in Bean Validation implementierten Einschränkungen fürNotNull,@NotEmpty und@NotBlank angesehen und deren Ähnlichkeiten und Unterschiede hervorgehoben.

Wie üblich sind alle in diesem Artikel gezeigten Codebeispieleover on GitHub verfügbar.