Hace ya mucho tiempo que venia perdiendo el tiempo validando manualmente los atributos que recibo en los requests hasta que descubri esta funcionalidad que permite realizar validaciones mediante el uso de annotations.
Incluido desde Java 7. No son necesarias nuevas dependencias
En el siguiente ejemplo, se puede ver un dto en el cual se valida que algunos campos no sean null, que no vengan vacios e incluso se verifica el formato mediante regular expressions
public class MyDto { @Pattern(regexp = "^[0-9A-Fa-f]{8}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{4}-[0-9A-Fa-f]{12}$", message = "Invalid format for uuid atribute") String uuid; @Pattern(regexp = "\\b(20|23|24|27|30|33|34)(\\D)?[0-9]{8}(\\D)?[0-9]", message = "Invalid cuit format for cuit atribute") @NotBlank(message = "cuit attribute is mandatory") @NotNull(message = "cuit attribute has to be present") String cuit; @NotNull(message = "bigDecimal attribute has to be present") BigDecimal bigDecimal = new BigDecimal(0); @NotNull (message = "date attribute is mandatory") @DateTimeFormat(pattern="yyyyMM") Date date; @ValueOfEnum(enumClass = DeclarationStatus.class) String status; }
Un aporte muy interesante es que permite customizar los mensajes que se generan para cada validacion.
Control absoluto del momento en que se ejecutan las validaciones
En nuestro codigo, podriamos por ejemplo asignar valores a estos atributos utilizando un constructor, los setters o mediante la automagia de reflection y spring; Esto ultimo nos puede generar una confusion…. de que manera sabe la JVM cuando es el momento en que YO PROGRAMADOR necesito validar todos estos campos?
Muy sencillo, en el siguiente ejemplo se le indica a al endpoint que debe realizar las validaciones aplicando la annotation @Valid en el atributo que recibimos como @RequestBody
@PostMapping("") public ResponseEntity<MyDto> create(@Valid @RequestBody MyDto myDto) { //do something }
Tambien se puede dar el caso en que dentro del codigo sea necesario construir una instancia del DTO y ejecutar luego las validaciones.
private MyDto doSomething(){ MyDto myDto = new MyDto(); myDto.setAttribute1("bla bla"); myDto.setAttribute2("bla bla"); myDto.setAttribute3("bla bla"); myDto.setAttribute3("bla bla"); ValidatorFactory factory = Validation.buildDefaultValidatorFactory(); Validator validator = factory.getValidator(); Set<ConstraintViolation<MyDto>> constraintViolations = validator.validate( myDto ); if(!constraintViolations.isEmpty()){ //throws custom Exception throw new InvalidMyDtoException(constraintViolations); } return myDto; }
Como se ve en el ejemplo, instanciamos un nuevo MyDto y seteamos sus atributos.
Para ejecutar las validaciones, es necesario contar con un ValidatorFactory al cual en su metodo validate() recibe como parametro a nuestro dto instanciado.
En caso de que una o mas validaciones encuentren errores, las mismas seran retornadas en un Set.
Yo acostumbro agruparlas en una exception y arrojarlas para que la capa web resuelva que hacer con eso.
Si queres checkear cuales son las validaciones que se pueden realizar, aca esta la documentacion oficial de Oracle
Es posible customizar tus propias validaciones
Las validaciones que trae java no son suficientes para las necesidades de tu proyecto? Vas a tener que esperar al proximo post.
Por Martin Larizzate, Java & Salesforce Developer