Creando custom constraints

Código Fuente: Ejemplo 1

Hibernate Validator viene con una serie de constraints ya creados, estos incluyen a los constraints que son parte del jsr303. En el siguiente link podemos encontrar una descripción de estos Constraints.

Por otro lado, nosotros también podemos crear nuestros propios constraints, los pasos necesarios para hacer esto, serán descritos a continuación.

Creando constraints simples

Vamos a crear dos constraints, uno a nivel de atributo y otro a nivel de clase.

Constraint a nivel de atributo

Vamos a crear un constraint que valide que un atributo de tipo String sólo tenga letras. Este constraint también debería poderse colocar al “getter” del atributo.

Necesitamos hacer lo siguiente:

- Crear la anotación que será usada para las validaciones.
   1: @Target({METHOD, FIELD, ANNOTATION_TYPE})

   2: @Retention(RUNTIME)

   3: @Constraint(validatedBy = OnlyLettersValidator.class)

   4: @Documented

   5: public @interface OnlyLetters {

   6:     String message() default "com.aw.jsr303.ejemplo001.constraints.onlyletters";

   7:     Class<?>[] groups() default {};

   8:     Class<? extends Payload>[] payload() default {};

   9: }

Línea 1: Se indica que la anotación puede usarse tanto en atributos, métodos y anotaciones (esto es necesario para crear constraint compuestos).

Línea 3:  Se define que la anotación será un constraint y que la clase que se encargará de realizar la validación será: “OnlyLettersValidator”

Línea 6: Se define el mensaje por default que se usará cuando falle esta validación.

Línea 7: Se define los grupos a los cuales puede pertenecer este constraint.

Línea 8:  Se define los “payload” que es una manera de agregar mayor información al Constraint, por ejemplo podríamos definir algunas interfaces que indiquen el nivel de severidad del constraint y enviar esta información como payload.

- Crear la clase que se encargue de ejecutar la validación.
   1: public class OnlyLettersValidator implements ConstraintValidator<OnlyLetters, String> {

   2:     public void initialize(OnlyLetters annotation) {

   3:     }

   4:     public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext) {

   5:         return allAreLetters(value);

   6:     }

   7:     private boolean allAreLetters(String str) {

   8:         if (str == null) {

   9:             return false;

  10:         }

  11:         int stringSize = str.length();

  12:         for (int i = 0; i < stringSize; i++) {

  13:             if (Character.isLetter(str.charAt(i)) == false) {

  14:                 return false;

  15:             }

  16:         }

  17:         return true;

  18:     }

  19: }

Línea 1: La clase que finalmente realizará la validación debe implementar la interface “ConstraintValidator” y debe poner como tipos, la anotación que usará para el constraint “OnlyLetters” y el tipo de dato que será validado “String” (ConstraintValidator)

Línea 2: Este método será llamado al inicio para obtener la información que se necesite de la anotación.

Línea 4: Este método es el que realiza la validación, en este caso va a recibir como parámetro el valor del atributo a ser validado.

Modo de uso del constraint
public class ComprobanteDePago {
@OnlyLetters
private String codigoInterno;

Constraint a nivel de clase

Vamos a crear un constraint a nivel de clase. Se validará que la clase ComprobanteDePago tenga obligatoriamente seteado el RUC siempre y cuando el tipo de documento sea FACTURA.

Necesitamos hacer lo siguiente:

- Crear la anotación que será usada para las validaciones.
   1: @Target({TYPE})

   2: @Retention(RUNTIME)

   3: @Constraint(validatedBy = RucInfoValidator.class)

   4: @Documented

   5: public @interface RucInfoChecker {

   6:     String message() default "com.aw.jsr303.ejemplo001.constraint.rucinfochecker";

   7:     Class<?>[] groups() default {};

   8:     Class<? extends Payload>[] payload() default {};

   9: }

Línea 1: Se indica que la anotación sólo se puede usar a nivel de clase.

Línea 3:  Se define que la anotación será un constraint y que la clase que se encargará de realizar la validación será: “RucInfoValidator”

- Crear la clase que se encargue de ejecutar la validación.
   1: public class RucInfoValidator implements ConstraintValidator<RucInfoChecker, ComprobanteDePago> {

   2:     public void initialize(RucInfoChecker annotation) {

   3:     }

   4:     public boolean isValid(ComprobanteDePago comprobanteDePago, ConstraintValidatorContext constraintValidatorContext) {

   5:         if (comprobanteDePago.getTipo() == ComprobanteTipo.FACTURA){

   6:             String ruc =comprobanteDePago.getRuc();

   7:             return ruc != null && !"".equals(ruc);

   8:         }

   9:         return true;

  10:     }

  11: }

Línea 1: La clase que finalmente realizará la validación debe implementar la interface “ConstraintValidator” y debe poner como tipos, la anotación que usará para el constraint “RucInfoChecker” y el tipo de dato que será validado “ComprobanteDePago” (ConstraintValidator)

Línea 2: Este método será llamado al inicio para obtener la información que se necesite de la anotación.

Línea 4: Este método es el que realiza la validación, en este caso va a recibir como parámetro la instancia de la clase DocumentoDePago.

Modo de uso del constraint
@RucInfoChecker
public class ComprobanteDePago {

Creando constraints compuestos

Los constraints compuestos son aquellos que agrupan más de un constraint. A continuación vamos a crear un constraint que agrupe @NotNull y @OnlyLetters. En estos casos sólo es necesario crear la anotación para el nuevo constraint.

   1: @NotNull

   2: @OnlyLetters

   3: @Target({METHOD, FIELD})

   4: @Retention(RUNTIME)

   5: @Constraint(validatedBy = {})

   6: @Documented

   7: @ReportAsSingleViolation

   8: public @interface OnlyLettersNotNull {

   9:     String message() default "com.aw.jsr303.ejemplo001.constraints.onlylettersnotnull";

  10:     Class<?>[] groups() default {};

  11:     Class<? extends Payload>[] payload() default {};

  12: }

Línea 1: Se indica que se incluirá el constraint @NotNull

Línea 2: Se indica que se incluirá el constraint @OnlyLetters

Línea 5:  Se define que la anotación será un constraint, no se indica la clase que será encargada de la validación, ya que es un constraint compuesto que en esencia sólo agrupa otros constraints.

Línea 7: Usando la anotación “@ReportAsSingleViolation” podemos indicar que por más que muchos constraints – que forman parte de este constraint compuesto – fallen, un sólo error debe ser reportado, sin esta anotación se reportarán todos los errores individuales que se encuentren.

Modo de uso del constraint

public class Item {
@OnlyLettersNotNull
private String coProducto;

Tags: , , ,

Deja un comentario

Usted debe ser conectado a publicar un comentario.