Código Fuente: Ejemplo 2
Para poder separar las validaciones de acuerdo a algún criterio debemos usar los grupos (“groups”)
Declaración de Grupos de validación
Normalmente para definir un grupo se usa una interface sin métodos, pero también se pueden usar clases. A continuación declararemos tres grupos de validación.
public interface TodasLasValidaciones {
}
public interface ValidacionesPrimerNivel {
}
public interface ValidacionesSegundoNivel {
}
Uso de los grupos de validación
Una vez definidos los grupos de validación los podemos usar en cualquier anotación. Por ejemplo:
1: public class Ciudadano {
2: @NotNull(message = "Se debe setear el estado civil", groups = ValidacionesPrimerNivel.class)
3: private EstadoCivil estadoCivil;
4: @Min(value = 18, groups = ValidacionesSegundoNivel.class)
5: private int edad;
6: @NotNull
7: private String documentoDeIdentidad;
8: }Línea 2-3 : Acá estamos indicando que la validación de @NotNull pertenece al grupo “ValidacionesPrimerNivel”.
Línea 4-5 : Acá estamos indicando que la validación de @Min pertenece al grupo “ValidacionesSegundoNivel”.
Línea 6-7 : Acá estamos indicando que la validación de @NotNull pertenece al grupo “Default”, que es un grupo especial al cual pertenecen todas las validaciones cuyo grupo no ha sido seteado.
También se debe tener en cuenta que el valor de “groups” puede ser un arreglo con varios grupos.
Validar usando grupos
Los grupos se pueden usar en cualquiera de los métodos:”validate”, “validateProperty” o “validateValue” de la clase Validator.
Ejecutando las validaciones por defecto
1: Validator validator = validatorFactory.getValidator();
2: Ciudadano ciudadano = new Ciudadano();
3: Set<ConstraintViolation<Ciudadano>> errors = validator.validate(ciudadano);
4: System.out.println("Errores: Nro:<" + errors.size()+">" + errors);
5: Set<ConstraintViolation<Ciudadano>> errorsDefault = validator.validate(ciudadano, Default.class);
6: System.out.println("Errores usando Default:Nro:<" + errorsDefault.size() +">" +errorsDefault);
Línea 3 : Se llama al método “validate” sin indicar ningún grupo.
Línea 5 : Se llama al método “validate” enviando como parámetro el grupo “Default”.
Se debe notar que la línea 3 y la línea 5 son equivalente en cuanto realizan la validación de todas las anotaciones que no tienen seteado explícitamente el atributo “groups”
Ejecutando las validaciones del primer nivel
Acá se van a ejecutar sólo las validaciones que pertenecen al grupo “ValidacionesPrimerNivel”.
Set<ConstraintViolation<Ciudadano>> errorsPrimerNivel = validator.validate(ciudadano,ValidacionesPrimerNivel.class);
System.out.println("Errores Primer Nivel:Nro:<" + errorsPrimerNivel.size()+">"+errorsPrimerNivel);
Podemos ver en el extracto anterior como enviamos el grupo como un parámetro más del método “validate”.
Ejecutando las validaciones del segundo nivel
Acá se van a ejecutar sólo las validaciones que pertenecen al grupo “ValidacionesSegundoNivel”.
Set<ConstraintViolation<Ciudadano>> errorsSegundoNivel = validator.validate(ciudadano,ValidacionesSegundoNivel.class);
System.out.println("Errores Segundo Nivel:Nro:<" + errorsSegundoNivel.size()+">"+errorsSegundoNivel);
Al igual que en caso anterior tenemos que enviar el grupo como parámetro al método “validate”
Ejecutar todas las validaciones
Para ejecutar todas las validaciones necesitamos enviar como parámetros del método “validate” todo los grupos que se han usado, incluyendo el “Default”, como se puede ver en el siguiente extracto:
Set<ConstraintViolation<Ciudadano>> errorsTodasLasValidaciones = validator.validate(ciudadano,Default.class,ValidacionesPrimerNivel.class,ValidacionesSegundoNivel.class);
System.out.println("Todos los Errores:Nro:<" + errorsTodasLasValidaciones.size()+">"+errorsTodasLasValidaciones);
Claro que también podemos crear un grupo que extienda todos los grupos.
public interface SuperGrupo extends Default,
ValidacionesPrimerNivel,
ValidacionesSegundoNivel {
}
y ejecutar la validación usando este nuevo grupo.
Set<ConstraintViolation<Ciudadano>> errorsSuperGrupo = validator.validate(ciudadano,SuperGrupo.class);
System.out.println("Todas las Validaciones :Nro:<" + errorsSuperGrupo.size()+">"+errorsSuperGrupo);
Ejecutar los grupos de validaciones en secuencia
Acá lo que se desea hacer, es poder ejecutar las validaciones teniendo en cuenta un orden entre los grupos que se desean validar, además de eso se necesita que si un grupo genera errores de validación ya no se ejecute el siguiente grupo de validaciones.
Para poder hacer lo anterior usaremos la anotación: “@GroupSequence”. Veamos el siguiente ejemplo:
@GroupSequence({Default.class,ValidacionesPrimerNivel.class,ValidacionesSegundoNivel.class})
public interface TodasLasValidaciones {
}
Acá estamos definiendo el grupo: “TodasLasValidaciones” y como estamos usando la anotación “@GroupSequence” podemos decir que:
- Este grupo incluye a los grupos: Default, ValidacionesPrimerNivel, ValidacionesSegundoNivel.
- Si fallan las validaciones de uno de los grupos, las validaciones de los siguientes grupos no serán ejecutadas. Por ejemplo si las validaciones del grupo Default fallan, las validaciones de los otros 2 grupos no serán ejecutadas.
Para ejecutar las validaciones de este grupo “TodasLasValidaciones” llamamos al método “validate” enviando como parámetro el grupo.
Set<ConstraintViolation<Ciudadano>> errorsTodasLasValidacionesEnSecuencia = validator.validate(ciudadano,TodasLasValidaciones.class);
System.out.println("Validación en secuencia:Nro:<" + errorsTodasLasValidacionesEnSecuencia.size()+">"+errorsTodasLasValidacionesEnSecuencia);
Modificando la secuencia de grupos de validación por defecto de una clase.
Para entender esto veamos el siguiente ejemplo:
Teniendo en cuenta la siguiente definición:
public class Carro {
@NotNull
private String numeroPlaca;
@NotNull(groups = ValidacionesPrimerNivel.class)
private Integer numeroAsientos;
Si ejecutamos lo siguiente:
Carro carro = new Carro();
Set<ConstraintViolation<Carro>> erroresEnCarro = validator.validate(carro);
System.out.println("Carro Errores: Nro:<" + erroresEnCarro.size()+">" + erroresEnCarro);
Solamente se ejecutará la validación del atributo “numeroPlaca” ya que tiene la anotación @NotNull sin ningún grupo, por lo cual se asume que pertenece al grupo “Default”. La validación sobre “numeroAsientos” no será ejecutada ya que pertenece al grupo “ValidacionPrimerNivel”.
Ahora lo que deseamos es que al llamar a “validator.validate(carro)” se ejecuten tanto las validaciones del grupo “Default” como las del grupo “ValidacionPrimerNivel”. Para poder hacer esto debemos agregar la anotación “@GroupSequence” a la clase Carro, la cual quedaría así:
@GroupSequence({Carro.class, ValidacionesPrimerNivel.class})
public class Carro {
De esta manera al llamar a: “validator.validate(carro)”, primero se ejecutarían las validaciones por defecto, y si no hay errores luego se ejecutarían las validaciones del grupo “ValidacionPrimerNivel”.
Tags: bean validation, groupsequence, java, jsr303
