No importa que tipo de aplicaciones desarrollemos, codificar validaciones es el pan nuestro de cada día. Durante años hemos estado usando una gran variedad de técnicas y marcos de trabajo para validación con buenos resultados. Sin embargo, desde hace algún tiempo contamos con un estándar para la validación en Java, la
especificación Bean Validation (JSR-303). La cuestión es: ¿merece la pena escribir (o rescribir) nuestras validaciones usando el estándar Bean Validation? ¿hay alguna ventaja práctica en usar JSR-303?
Antes de nada, escribamos un validador (una restricción si usamos la nomenclatura JSR-303) y después usémoslo en nuestro código, para ver de que estamos hablando.
Crear una restricción JSR-303Una restricción JSR-303 es tan solo una simple anotación Java. Por ejemplo, si queremos validar ISBNs hemos de crear una anotación @ISBN como la siguiente:
package org.openxava.books.constraints;
import static java.lang.annotation.ElementType.*;
import static java.lang.annotation.RetentionPolicy.*;
import java.lang.annotation.*;
import javax.validation.*;
import org.openxava.books.constraints.impl.*;
@Constraint(validatedBy = ISBNValidator.class) // ISBNValidator contiene la lógica de validación
@Target({ METHOD, FIELD })
@Retention(RUNTIME)
public @interface ISBN {
String message() default "{org.openxava.books.constraints.ISBN.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
Lo importante aquí es la anotación @Constraint, que además de marcar esta anotación como una "restricción", indica la clase validador, ISBNValidator, la cual contiene la lógica de validación:
package org.openxava.books.constraints.impl;
import javax.validation.*;
import org.openxava.books.constraints.*;
public class ISBNValidator implements ConstraintValidator<ISBN, String> {
private static org.apache.commons.validator.ISBNValidator validator =
new org.apache.commons.validator.ISBNValidator(); // Validator from commons validator
public void initialize(ISBN isbn) {
}
public boolean isValid(String value, ConstraintValidatorContext ctx) { // The validation logic
if (value == null || value.trim().equals("")) return true;
return validator.isValid(value); // We simply delegate in commons validator
}
}
El validador tiene que implementar ConstraintValidator, por tanto ha de tener los métodos initialize() y isValid(), este último contiene la lógica de validación. En este caso simplemente delegamos en un validador del proyecto Commons Validator de Apache .
Podemos ver como crear un validador es bastante fácil. Ahora bien, ¿cómo podemos usar esta validación en nuestra aplicación?
Usar el validadorLa especificación JSR-303 trata sobre como se definen los validadores, pero no sobre como se han de usar y como se comportan en nuestra aplicación, esto depende del marco de trabajo que estemos usando. JPA2 y JSF2 cuentan con integración de Bean Validation, además muchos marcos de trabajo modernos tienen soporte para JSR-303 también. En este caso vamos a desarrollar una miniaplicación usando el marco de trabajo
OpenXava y usaremos la anotación @ISBN que hemos desarrollado. No te preocupes, desarrollar una aplicación OpenXava es breve, dado que sólo necesitamos escribir las clases del dominio.
Después de crear un proyecto de OpenXava nuevo (
ejecutando una tarea ant) le añadimos las clases Author y Book.
Author.groovy:
package org.openxava.books.model
import javax.persistence.*
import org.openxava.model.*
import org.openxava.annotations.*
@Entity
class Author extends Identifiable {
@Required
String name
}
Book.groovy:
package org.openxava.books.model
import org.openxava.model.*;
import org.openxava.annotations.*;
import org.openxava.books.constraints.*;
import javax.persistence.*;
@Entity
class Book extends Identifiable {
@Required @Column(length=60)
String title
@ManyToOne(fetch=FetchType.LAZY)
@DescriptionsList
Author author
@Column(length=10)
@ISBN
String isbn
}
Aunque podríamos haber escrito las clases con Java, hemos escogido usar Groovy. Sí, el desarrollo web Groovy sin Grails es posible. Sin embargo, lo importante aquí es la anotación @ISBN en la propiedad isbn. No necesitamos hacer más para ver la validación funcionando. Si vamos a http://localhost:8080/Books/modules/Book, e intentamos añadir un libro con un ISBN incorrecto obtendremos algo como esto:

Como se puede ver usar la validación @ISBN en nuestra aplicación es una tarea totalmente declarativa y por lo tanto extremadamente fácil.
¿Por qué deberíamos usar Bean Validation?
Aunque JSR-303 es fácil de usar y lo suficientemente versatil como para cubrir nuestras necesidades de validación, tampoco es algo espectacular, y posiblemente no sea mucho mejor que nuestra solución actual de validación, así que ¿por qué deberiamos usarlo? Porque lo soportan JPA2, JSF2, Spring Roo, Wicket, OpenXava, Tapestry, etc. además de formar parte del estándar Java EE 6. Por lo tanto, nos da más libertad, porque nuestro código es menos dependiente del marco de aplicaciones que estemos usando, así es más fácil migrar nuestro código (al menos la parte del modelo) de Wicket a Tapestry, o de Spring Roo a OpenXava.
Usa el estándar Bean Validation. ¡Sé libre!
Referencias