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

1. Übersicht

Die Bean-Validierung ist eine Standard-Validierungsspezifikation, mit der wir Domänenobjekte mithilfe einer Reihe von Einschränkungen, die in Form von Anmerkungen deklariert sind, einfach validieren können .

Insgesamt ist die Verwendung von Bean-Validierungsimplementierungen wie Hibernate Validator recht unkompliziert. Es lohnt sich jedoch, einige subtile, jedoch relevante Unterschiede in Bezug auf die Implementierung einiger dieser Einschränkungen zu untersuchen.

In diesem Tutorial werden wir die Unterschiede zwischen den vor Ort @NotNull , @NotEmpty, und @NotBlank Einschränkungen .

2. Die Maven-Abhängigkeiten

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

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

Hier ist der relevante Abschnitt unserer Datei pom.xml :

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

Wir werden JUnit und AssertJ in unseren Komponententests verwenden. Überprüfen Sie daher unbedingt die neuesten Versionen von Hibernate-Validator, GlassFishs EL-Implementierung, Junit und Assertj-Core auf Maven Central.

3. Die @ NotNull- Einschränkung

Auch in Zukunft wollen wir eine naive Umsetzung UserNotNull Domain - Klasse und beschränken ihren Namen Feld mit der @NotNull Anmerkung:

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 erlaubt die @ NotNull- Einschränkung keine Nullwerte für die eingeschränkten Felder. Trotzdem können die Felder leer sein.

Um dies besser zu verstehen, schauen wir uns die isValid () -Methode der NotNullValidator- Klasse an , die von der @ NotNull- Einschränkung verwendet wird. Die Methodenimplementierung ist wirklich trivial:

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

Wie oben gezeigt, darf ein mit @NotNull eingeschränktes Feld (z. B. CharSequence , Collection , Map oder Array) nicht null sein. Ein leerer Wert ist jedoch völlig legal .

4. Die @ NotEmpty- Einschränkung

Implementieren wir nun eine UserNotEmpty- Beispielklasse und verwenden die @ NotEmpty- Einschränkung:

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

Mit der Klasse vorhanden, wir testen es nur durch unterschiedliche Werte an die Zuordnung Name Feld:

@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 @NotEmpty verwendet die isValid () -Implementierung der @ NotNull- Klasse 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) größer als Null ist.

Kurz gesagt bedeutet dies, dass ein mit @NotEmpty eingeschränktes Feld (z. B. CharSequence , Collection , Map oder Array) nicht null sein darf und seine Größe / Länge größer als null sein muss .

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

Auf diese Weise würden wir auch erzwingen, dass die minimalen und maximalen 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

Ebenso können wir ein Klassenfeld mit der Annotation @NotBlank einschrä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 @ NotBlank- Einschränkung funktioniert:

@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 @NotBlank verwendet die NotBlankValidator- Klasse, 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; } 

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

Die @ noNull- Klasse 'isValid () -Methode wird nach der @ NotBlank- Klasse' isValid () aufgerufen, wodurch Nullwerte verboten werden.

Einfach ausgedrückt darf ein mit @NotBlank eingeschränktes String- Feld nicht null sein und die zugeschnittene Länge muss größer als Null sein .

6. Ein Nebeneinander-Vergleich

Bisher haben wir uns eingehend mit der Funktionsweise der Einschränkungen @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: Eine eingeschränkte CharSequence , Collection , Map oder Array ist gültig, solange sie nicht null ist, aber leer sein kann
  • @NotEmpty: Eine eingeschränkte CharSequence , Collection , Map oder Array ist gültig, solange sie nicht null ist und ihre Größe / Länge größer als null ist
  • @NotBlank: Ein eingeschränkter String ist gültig, solange er nicht null ist und die zugeschnittene Länge größer als null ist

7. Fazit

In diesem Artikel haben wir uns die in der Bean-Validierung implementierten Einschränkungen NotNull , @NotEmpty und @NotBlank angesehen und ihre Ähnlichkeiten und Unterschiede hervorgehoben.

Wie üblich sind alle in diesem Artikel gezeigten Codebeispiele auf GitHub verfügbar.