Introduction à Apache BVal

Introduction à Apache BVal

1. introduction

Dans cet article, nous allons jeter un œil auxApache BVal library’s implementation of the Java Bean Validation specification (JSR 349).

2. Dépendances Maven

Pour utiliserApache BVal, nous devons d'abord ajouter les dépendances suivantes à notre fichierpom.xml:


    org.apache.bval
    bval-jsr
    1.1.2


    javax.validation
    validation-api
    1.1.0.Final

Les contraintes personnaliséesBVal se trouvent dans la dépendance optionnellebval-extras:


    org.apache.bval
    bval-extras
    1.1.2

Les dernières versions debval-jsr,bval-extras etvalidation-api peuvent être téléchargées depuis Maven Central.

3. Application de contraintes

Apache BVal fournit des implémentations pour toutes les contraintes définies dans le packagejavax.validation. Afin d'appliquer une contrainte à une propriété d'un bean, on peutadd the constraint annotation to the property declaration.

Créons une classeUser qui a quatre attributs, puis appliquons les annotations@NotNull,@Size et@Min:

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. Valider les haricots

Pour valider les contraintes appliquées sur la classeUser, nous devons obtenir une instanceValidatorFactory et une ou plusieurs instancesValidator.

4.1. Obtention d'unValidatorFactory

Il est recommandé par la documentation deApache BVal d'obtenir une seule instance de cette classe, car la création d'usine est un processus exigeant:

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

4.2. Obtention d'unValidator

Ensuite, nous devons obtenir une instance deValidator à partir desvalidatorFactory définis ci-dessus:

Validator validator = validatorFactory.getValidator();

This is a thread-safe implementation, nous pouvons donc réutiliser en toute sécurité des instances déjà créées.

La classeValidator propose trois méthodes pour déterminer la validité d'un bean:validate(),validateProperty() etvalidateValue().

Chacune de ces méthodes renvoie un ensemble d'objetsConstraintViolation contenant des informations sur la contrainte qui n'a pas été respectée.

4.3. APIvalidate()

La méthodevalidate() vérifie la validité du bean entier, ce qui signifie qu'ilverifies all the constraints applied to properties of an object est passé en paramètre.

Créons un testJUnit où nous définissons un objetUser et utilisons la méthodevalidate() pour tester ses propriétés:

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

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

4.4. APIvalidateProperty()

La méthodevalidateProperty() peut être utilisée pourvalidate a single property of a bean.

Créons un testJUnit dans lequel nous définirons un objetUser avec une propriétéage inférieure à la valeur minimale requise de 18 et vérifierons que la validation de cette propriété entraîne une violation:

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

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

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

4.5. APIvalidateValue()

La méthodevalidateValue() peut être utilisée pourcheck if some value would be a valid value for a property of a bean avant de la définir sur le bean.

Créons un testJUnit avec un objetUser, puis vérifions que la valeur20 est une valeur valide pour la propriétéage:

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

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

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

4.6. Fermeture desValidatorFactory

After using the ValidatorFactory, we must remember to close it à la fin:

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

5. Contraintes non -JSR

La bibliothèqueApache BVal fournit également unseries of constraints that are not a part of the JSR specification et fournit des capacités de validation supplémentaires et plus puissantes.

Le packagebval-jsr contient deux contraintes supplémentaires:@Email pour valider une adresse e-mail valide et@NotEmpty pour s'assurer qu'une valeur n'est pas vide.

Le reste des contraintes personnaliséesBVal sont fournies dans le package optionnelbval-extras.

Ce package contient desconstraints for verifying various number formats tels que l'annotation@IBAN qui garantit qu'un nombre est un numéro de compte bancaire international valide, l'annotation@Isbn qui vérifie un numéro de livre standard valide et le@EAN13 annotation pour vérifier un numéro d'article international.

La bibliothèque fournit égalementannotations for ensuring the validity of various types of credit card numbers:@AmericanExpress,@Diners,@Discover,@Mastercard et@Visa.

Vous pouvezdetermine if a value contains a valid domain or Internet Address en utilisant les annotations@Domain et@InetAddress.

Et enfin, le package contient les annotations@Directory et@NotDirectory pourverifying whether a File object is a directory or not.

Définissons des propriétés supplémentaires sur notre classeUser et appliquons-leur certaines des annotations non -JSR:

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
}

Les contraintes peuvent être testées de manière similaire aux contraintesJSR:

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

Bien que ces annotations supplémentaires soient pratiques pour les besoins de validation potentiels, le seul inconvénient de l'utilisation d'annotations qui ne font pas partie de la spécificationJSR est que vous ne pouvez pas facilement passer à une implémentation deJSRdifférente si cela devenait nécessaire plus tard. .

6. Contraintes personnalisées

Afin de définir nos propres contraintes, nous devons d’abord créer une annotation en respectant la syntaxe standard.

Créons une annotationPassword qui définira les conditions que le mot de passe d’un utilisateur doit remplir:

@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[] payload() default {};

    int length() default 6;

    int nonAlpha() default 1;
}

The actual validation of the password value is done in a class that implements the ConstraintValidator interface - dans notre cas, la classePasswordValidator. Cette classe remplace la méthodeisValid() et vérifie si la longueur dupassword est inférieure à l'attributlength, et si elle contient moins que le nombre spécifié de caractères non alphanumériques dans lenonAlphaattribut:

public class PasswordValidator
  implements ConstraintValidator {

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

Appliquons notre contrainte personnalisée à la propriétépassword de la classeUser:

@Password(length = 8)
private String password;

Nous pouvons créer un testJUnit pour vérifier qu'une valeurpassword non valide entraîne une violation de contrainte:

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

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

Créons maintenant un testJUnit dans lequel nous vérifions une valeurpassword valide:

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

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

7. Conclusion

Dans cet article, nous avons illustré l'utilisation de l'implémentation de la validation du beanApache BVal.

Le code source complet de cet article se trouveover on GitHub.