Einführung in Apache BVal

1. Einführung

In diesem Artikel betrachten wir die Implementierung der Java Bean Validation -Spezifikation ( JSR 349 ​​ ) der Apache BVal -Bibliothek.

2. Abhängigkeiten von Maven

Um Apache BVal verwenden zu können, müssen wir zunächst die folgenden Abhängigkeiten in unsere pom.xml -Datei einfügen:

<dependency>
    <groupId>org.apache.bval</groupId>
    <artifactId>bval-jsr</artifactId>
    <version>1.1.2</version>
</dependency>
<dependency>
    <groupId>javax.validation</groupId>
    <artifactId>validation-api</artifactId>
    <version>1.1.0.Final</version>
</dependency>

Benutzerdefinierte BVal -Einschränkungen können in der optionalen bval-extras -Abhängigkeit gefunden werden:

<dependency>
    <groupId>org.apache.bval</groupId>
    <artifactId>bval-extras</artifactId>
    <version>1.1.2</version>
</dependency>

Die neuesten Versionen von https://search.maven.org/classic/ search%7Cga%7C1%7Ca%3A%22bval-jsr%22[bval-jsr], https://search.maven.org/classic/ search% 7Cga% 7C1% 7Capache% 20bval% 20extras[bval-extras]und validation- api kann von Maven Central heruntergeladen werden.

3. Anwenden von Einschränkungen

Apache BVal bietet Implementierungen für alle im javax.validation -Paket definierten Einschränkungen. Um eine Einschränkung auf eine Eigenschaft eines Beans anzuwenden, können wir die Einschränkungsannotation zur Eigenschaftendeklaration hinzufügen .

Erstellen wir eine User -Klasse mit vier Attributen und wenden Sie die Annotationen @ NotNull , @ Size und @ Min an:

public class User {

    @NotNull
    private String email;

    private String password;

    @Size(min=1, max=20)
    private String name;

    @Min(18)
    private int age;

   //standard constructor, getters, setters
}

4. Bohnen validieren

Um die auf die User -Klasse angewendeten Einschränkungen zu überprüfen, müssen wir eine ValidatorFactory -Instanz und eine oder mehrere Validator -Instanzen anfordern.

4.1. Beziehen einer ValidatorFactory

In der Apache BVal -Dokumentation wird empfohlen, eine einzelne Instanz dieser Klasse zu erhalten, da die Fabrikerstellung ein anspruchsvoller Prozess ist:

ValidatorFactory validatorFactory
  = Validation.byProvider(ApacheValidationProvider.class)
  .configure().buildValidatorFactory();

4.2. Validator erhalten

Als Nächstes müssen wir eine Validator -Instanz von der oben definierten validatorFactory erhalten:

Validator validator = validatorFactory.getValidator();
  • Dies ist eine Thread-sichere Implementierung ** , sodass wir bereits erstellte Instanzen sicher wiederverwenden können.

Die Validator -Klasse bietet drei Methoden zur Bestimmung der Gültigkeit einer Bean: validate () , validateProperty () und validateValue () .

Jede dieser Methoden gibt eine Gruppe von ConstraintViolation -Objekten zurück, die Informationen über die Einschränkung enthalten, die nicht eingehalten wurde.

4.3. validate () API

Die Methode validate () überprüft die Gültigkeit der gesamten Bean, dh sie prüft alle Einschränkungen, die auf Eigenschaften eines Objekts angewendet werden, das als Parameter übergeben wird.

Erstellen wir einen JUnit -Test, in dem wir ein User -Objekt definieren und die validate () -Methode zum Testen seiner Eigenschaften verwenden:

@Test
public void givenUser__whenValidate__thenValidationViolations() {
    User user
      = new User("[email protected]", "pass", "nameTooLong______________________________", 15);

    Set<ConstraintViolation<User>> violations = validator.validate(user);
    assertTrue("no violations", violations.size() > 0);
}

4.4. validateProperty () API

Die Methode validateProperty () kann verwendet werden, um eine einzelne Eigenschaft einer Bean zu überprüfen.

Erstellen Sie einen JUnit -Test, in dem wir ein User -Objekt mit einer age -Eigenschaft definieren, die unter dem erforderlichen Mindestwert von 18 liegt, und überprüfen, ob die Überprüfung dieser Eigenschaft zu einer Verletzung führt:

@Test
public void givenInvalidAge__whenValidateProperty__thenConstraintViolation() {
    User user = new User("[email protected]", "pass", "Ana", 12);

    Set<ConstraintViolation<User>> propertyViolations
      = validator.validateProperty(user, "age");

    assertEquals("size is not 1", 1, propertyViolations.size());
}

4.5. validateValue () API

Mit der Methode validateValue () kann geprüft werden, ob ein Wert ein gültiger Wert für eine Eigenschaft eines Beans ist , bevor er für das Bean festgelegt wird.

Erstellen Sie einen JUnit -Test mit einem User -Objekt und überprüfen Sie, ob der Wert 20 ein gültiger Wert für die age -Eigenschaft ist:

@Test
public void givenValidAge__whenValidateValue__thenNoConstraintViolation() {
    User user = new User("[email protected]", "pass", "Ana", 18);

    Set<ConstraintViolation<User>> valueViolations
      = validator.validateValue(User.class, "age", 20);

    assertEquals("size is not 0", 0, valueViolations.size());
}

4.6. ValidatorFactory schließen

  • Nachdem Sie die ValidatorFactory verwendet haben, müssen Sie daran denken, ** am Ende zu schließen:

if (validatorFactory != null) {
    validatorFactory.close();
}

5. Nicht- JSR -Einschränkungen

Die Apache BVal -Bibliothek stellt auch eine Reihe von Einschränkungen bereit, die nicht Teil der JSR -Spezifikation sind ** und zusätzliche und leistungsfähigere Validierungsfunktionen bieten.

Das Paket bval-jsr enthält zwei zusätzliche Einschränkungen: @ Email zum Überprüfen einer gültigen E-Mail-Adresse und @ NotEmpty zum Sicherstellen, dass ein Wert nicht leer ist.

Der Rest der benutzerdefinierten BVal -Einschränkungen ist im optionalen Paket bval-extras enthalten.

Dieses Paket enthält Einschränkungen für die Überprüfung verschiedener Zahlenformate , z. B. die Annotation @ IBAN , die sicherstellt, dass eine Nummer eine gültige internationale Bankkontonummer ist, die Annotation @ Isbn , die eine gültige Standardbuchnummer überprüft, und die Annotation @ EAN13 für Überprüfung einer internationalen Artikelnummer.

Die Bibliothek enthält Anmerkungen, um die Gültigkeit verschiedener Arten von Kreditkartennummern sicherzustellen : @ AmericanExpress , @ Diners , @ Discover , @ Mastercard und @ Visa .

Sie können feststellen, ob ein Wert eine gültige Domäne oder Internetadresse enthält , indem Sie die Annotationen @ Domain und @ InetAddress verwenden.

Schließlich enthält das Paket die Annotationen @ Directory und @ NotDirectory für die Überprüfung, ob ein File -Objekt ein Verzeichnis ist oder nicht .

Definieren Sie zusätzliche Eigenschaften für unsere User -Klasse und wenden Sie einige der Nicht- JSR -Anmerkungen an:

public class User {

    @NotNull
    @Email
    private String email;

    @NotEmpty
    private String password;

    @Size(min=1, max=20)
    private String name;

    @Min(18)
    private int age;

    @Visa
    private String cardNumber = "";

    @IBAN
    private String iban = "";

    @InetAddress
    private String website = "";

    @Directory
    private File mainDirectory = new File(".");

   //standard constructor, getters, setters
}

Die Einschränkungen können auf ähnliche Weise wie die JSR -Einschränkungen getestet werden:

@Test
public void whenValidateNonJSR__thenCorrect() {
    User user = new User("[email protected]", "pass", "Ana", 20);
    user.setCardNumber("1234");
    user.setIban("1234");
    user.setWebsite("10.0.2.50");
    user.setMainDirectory(new File("."));

    Set<ConstraintViolation<User>> violations
      = validator.validateProperty(user,"iban");

    assertEquals("size is not 1", 1, violations.size());

    violations = validator.validateProperty(user,"website");

    assertEquals("size is not 0", 0, violations.size());

    violations = validator.validateProperty(user, "mainDirectory");

    assertEquals("size is not 0", 0, violations.size());
}

Diese zusätzlichen Anmerkungen sind zwar für potenzielle Validierungsanforderungen geeignet, der einzige Nachteil der Verwendung von Anmerkungen, die nicht Teil der JSR -Spezifikation sind, besteht darin, dass Sie nicht leicht zu einer anderen JSR -Implementierung wechseln können, falls dies später erforderlich wird.

6. Benutzerdefinierte Einschränkungen

Um unsere eigenen Einschränkungen zu definieren, müssen Sie zunächst eine Annotation gemäß der Standardsyntax erstellen.

Erstellen Sie eine Password -Anmerkung, die die Bedingungen definiert, die ein Benutzerpasswort erfüllen muss:

@Constraint(validatedBy = { PasswordValidator.class })
@Target({METHOD, FIELD, ANNOTATION__TYPE, CONSTRUCTOR, PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
public @interface Password {
    String message() default "Invalid password";

    Class<?>[]groups() default {};

    Class<? extends Payload>[]payload() default {};

    int length() default 6;

    int nonAlpha() default 1;
}
  • Die eigentliche Validierung des password -Werts erfolgt in einer Klasse, die das ConstraintValidator -Interface implementiert ** - in unserem Fall die PasswordValidator -Klasse. Diese Klasse überschreibt die Methode isValid () und überprüft, ob die Länge des password kürzer ist als das Attribut length und ob sie weniger als die angegebene Anzahl nicht alphanumerischer Zeichen im Attribut nonAlpha enthält:

public class PasswordValidator
  implements ConstraintValidator<Password, String> {

    private int length;
    private int nonAlpha;

    @Override
    public void initialize(Password password) {
        this.length = password.length();
        this.nonAlpha = password.nonAlpha();
    }

    @Override
    public boolean isValid(String value, ConstraintValidatorContext ctx) {
        if (value.length() < length) {
            return false;
        }
        int nonAlphaNr = 0;
        for (int i = 0; i < value.length(); i++) {
            if (!Character.isLetterOrDigit(value.charAt(i))) {
                nonAlphaNr++;
            }
        }
        if (nonAlphaNr < nonAlpha) {
            return false;
        }
        return true;
    }
}

Wenden wir unsere benutzerdefinierte Einschränkung auf die password -Eigenschaft der User -Klasse an:

@Password(length = 8)
private String password;

Wir können einen JUnit -Test erstellen, um zu überprüfen, ob ein ungültiger Kennwort Wert zu einer Einschränkungsverletzung führt:

@Test
public void givenValidPassword__whenValidatePassword__thenNoConstraintViolation() {
    User user = new User("[email protected]", "password", "Ana", 20);
    Set<ConstraintViolation<User>> violations
      = validator.validateProperty(user, "password");

    assertEquals(
      "message incorrect",
      "Invalid password",
      violations.iterator().next().getMessage());
}

Nun erstellen wir einen JUnit -Test, in dem wir einen gültigen __Kennwortwert überprüfen:

@Test
public void givenValidPassword__whenValidatePassword__thenNoConstraintViolation() {
    User user = new User("[email protected]", "password#", "Ana", 20);

    Set<ConstraintViolation<User>> violations
      = validator.validateProperty(user, "password");
    assertEquals("size is not 0", 0, violations.size());
}

7. Fazit

In diesem Artikel haben wir die Verwendung der Validierungsimplementierung Apache BVal Bean veranschaulicht.

Den vollständigen Quellcode für diesen Artikel finden Sie auf GitHub unter https://github.com/eugenp/tutorials/tree/master/apache-bval