Introdução ao Apache BVal
1. Introdução
Neste artigo, daremos uma olhada emApache BVal library’s implementation of the Java Bean Validation specification (JSR 349).
2. Dependências do Maven
Para usarApache BVal, primeiro precisamos adicionar as seguintes dependências ao nosso arquivopom.xml:
org.apache.bval
bval-jsr
1.1.2
javax.validation
validation-api
1.1.0.Final
RestriçõesBVal personalizadas podem ser encontradas na dependênciabval-extras opcional:
org.apache.bval
bval-extras
1.1.2
As versões mais recentes debval-jsr,bval-extras evalidation-api podem ser baixadas do Maven Central.
3. Aplicando restrições
Apache BVal fornece implementações para todas as restrições definidas no pacotejavax.validation. Para aplicar uma restrição a uma propriedade de um bean, podemosadd the constraint annotation to the property declaration.
Vamos criar uma classeUser que tem quatro atributos e, em seguida, aplicar as anotações@NotNull,@Size e@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. Validando Feijões
Para validar as restrições aplicadas na classeUser, precisamos obter uma instânciaValidatorFactorye uma ou mais instânciasValidator.
4.1. Obtendo umValidatorFactory
É recomendado pela documentaçãoApache BVal obter uma única instância desta classe, pois a criação da fábrica é um processo exigente:
ValidatorFactory validatorFactory
= Validation.byProvider(ApacheValidationProvider.class)
.configure().buildValidatorFactory();
4.2. Obtendo umValidator
Em seguida, precisamos obter uma instânciaValidator devalidatorFactory definido acima:
Validator validator = validatorFactory.getValidator();
This is a thread-safe implementation, para que possamos reutilizar com segurança as instâncias já criadas.
A classeValidator oferece três métodos para determinar a validade de um bean:validate(),validateProperty()evalidateValue().
Cada um desses métodos retorna um conjunto de objetosConstraintViolation que contêm informações sobre a restrição que não foi obedecida.
4.3. APIvalidate()
O métodovalidate() verifica a validade de todo o bean, o que significa que éverifies all the constraints applied to properties of an object que é passado como parâmetro.
Vamos criar um testeJUnit onde definimos um objetoUser e usamos o métodovalidate() para testar suas propriedades:
@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()
O métodovalidateProperty() pode ser usado paravalidate a single property of a bean.
Vamos criar um testeJUnit no qual definiremos um objetoUser com uma propriedadeage menor que o valor mínimo exigido de 18 e verificar se a validação dessa propriedade resulta em uma violação:
@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()
O métodovalidateValue() pode ser usado paracheck if some value would be a valid value for a property of a bean antes de defini-lo no bean.
Vamos criar um testeJUnit com um objetoUser e, em seguida, verificar se o valor20 é um valor válido para a propriedadeage:
@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. Fechando oValidatorFactory
After using the ValidatorFactory, we must remember to close it no final:
if (validatorFactory != null) {
validatorFactory.close();
}
5. Restrições não -JSR
A bibliotecaApache BVal também fornece umseries of constraints that are not a part of the JSR specificatione fornece recursos de validação adicionais e mais poderosos.
O pacotebval-jsr contém duas restrições adicionais:@Email para validar um endereço de e-mail válido e@NotEmpty para garantir que um valor não esteja vazio.
O restante das restriçõesBVal personalizadas são fornecidas no pacote opcionalbval-extras.
Este pacote contémconstraints for verifying various number formats, como a anotação@IBAN que garante que um número é um número de conta bancária internacional válido, a anotação@Isbn que verifica um número de livro padrão válido e o@EAN13 anotação para verificar um número de artigo internacional.
A biblioteca também forneceannotations for ensuring the validity of various types of credit card numbers:@AmericanExpress,@Diners,@Discover,@Mastercard e@Visa.
Você podedetermine if a value contains a valid domain or Internet Address usando as anotações@Domaine@InetAddress.
E, finalmente, o pacote contém as anotações@Directorye@NotDirectory paraverifying whether a File object is a directory or not.
Vamos definir propriedades adicionais em nossa classeUser e aplicar algumas das anotações não -JSR a elas:
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
}
As restrições podem ser testadas de maneira semelhante às restriçõesJSR:
@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());
}
Embora essas anotações adicionais sejam convenientes para necessidades de validação em potencial, a única desvantagem de usar anotações que não fazem parte da especificaçãoJSR é que você não pode alternar facilmente para uma implementaçãoJSR diferente, caso isso se torne necessário mais tarde .
6. Restrições personalizadas
Para definir nossas próprias restrições, primeiro precisamos criar uma anotação seguindo a sintaxe padrão.
Vamos criar uma anotaçãoPassword que definirá as condições que a senha de um usuário deve satisfazer:
@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;
}
The actual validation of the password value is done in a class that implements the ConstraintValidator interface - no nosso caso, a classePasswordValidator. Esta classe substitui o métodoisValid() e verifica se o comprimento dopassword é menor que o atributolength e se contém menos do que o número especificado de caracteres não alfanuméricos emnonAlphaatributo s:
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;
}
}
Vamos aplicar nossa restrição personalizada à propriedadepassword da classeUser:
@Password(length = 8)
private String password;
Podemos criar um testeJUnit para verificar se um valorpassword inválido resulta em uma violação de restrição:
@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());
}
Agora vamos criar um testeJUnit no qual verificamos um valorpassword válido:
@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. Conclusão
Neste artigo, exemplificamos o uso da implementação de validação de beanApache BVal.
O código-fonte completo deste artigo pode ser encontradoover on GitHub.