A API Bean Validations permite incluir anotações no código que dizem como os campos serão validados pela aplicação.
Abaixo temos um exemplo de algumas anotações básicas existentes na API:
public class User {
@NotNull @Email
private String email;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
}
@ValidateParams
public class UserService {
public void createUser(@Email String email,
@NotNull String name) {
...
}
}
Junto com a estrutura desenvolvida no Identity, tais anotações são validadas automaticamente quando a classe ou o método possui a anotação @ValidateParams.
Para isso, as anotações de validação devem ser colocadas na classe de Implementação e também nas Interfaces onde os métodos são definidos.
A anotação @ValidateParams deve ser colocada somente na implementação.
public class ServiceInterface {
public void createUser(@Email String email, @NotNull String name);
}
@ValidateParams
public class ServiceImpl {
public void createUser(@Email String email, @NotNull String name){
//...
}
}
Agrupamento de Validações
É possível agrupar validações em uma mesma validação personalizada, conforme exemplo abaixo, que faz várias validações em um único parâmetro.:
@ValidateParams
public class CarService {
public void findCar(@NotNull @NotBlank @NotEmpty @Pattern(regex="[A-Z]{3}\d{4}") String plate) {
...
}
}
Para simplificar, poderíamos criar uma validação personalizada, combinando todas essas validações em uma única validação (@Plate)
@ValidateParams
public class CarService {
public void findCar(@Plate String plate) {
...
}
}
Para isso, é necessário criar uma anotação nova, seguindo alguns padrões.
// agrupamento das validações utilizadas
@NotNull
@NotEmpty
@NotBlank
@Pattern(regex="[A-Z]{3}\d{4}")
// Elementos onde essa anotação pode ser colocada
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
// Anotação que indica que esta é uma anotação de validação
@Constraint(validatedBy = {})
// Anotação que indica que todas as anotações agrupadas serão tratadas como uma unica violação
@ReportAsSingleViolation
public @interface Plate {
// Identificação da mensagem a ser exibida
String message() default "{com.totvs.custom.validation.plate.message}";
// Permite definir grupos com outras anotações
Class<?>[] groups() default {};
// Área para inclusão de dados genéricos
Class<? extends Payload>[] payload() default {};
}
É possível também criar validadores customizados para as anotações.
Seguindo o exemplo acima, poderíamos incluir uma verificação no Detran, para verificar se a placa é realmente válida, para isso, é necessário escrever código para realizar essa consulta.
Com algumas modificações, é possível incluir um validador customizado para essa tarefa:
@NotNull
@NotEmpty
@NotBlank
@Pattern(regex="[A-Z]{3}\d{4}")
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
// Classe que irá fazer a validação no Detran
@Constraint(validatedBy = DetranValidator.class)
@ReportAsSingleViolation
public @interface Plate{
String message() default "{com.totvs.custom.validation.plate.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
public class DetranValidator implements ConstraintValidator<Plate, String> {
private CaseMode caseMode;
@Override
public void initialize(CheckCase constraintAnnotation) {
this.caseMode = constraintAnnotation.value();
}
@Override
public boolean isValid(String object, ConstraintValidatorContext constraintContext) {
var validDetran = pesquisaDetran(); // logica de pesquisa no detran
if ( validDetran ) {
return true;
}
return false;
}
}