Hibernate Validator, y como definir las validaciones sobre los objetos de negocio

1
20128

Creación: 14-06-2008

Índice de contenidos

1.Introducción
2. Entorno
3.Configuración del entorno de desarrollo
4.Validaciones predefinidas
5.Añadiendo validaciones a nuestro POJO
6.Ejemplos de como se valida nuestro POJO
7.Recursos
8.Conclusiones
9.Sobre el autor

1. Introducción

Cuando construimos aplicaciones, lo normal es que tengamos que hacer validaciones de las entradas del usuario. Frameworks como JSF o Struts nos suelen proporcionar ayudas para que podamos definir más o menos de manera fácil estas validaciones en la vista.

Los problemas que tiene esto son:

  • Nos podemos encontrar repitiendo las mismas validaciones en diferentes formularios de nuestra aplicación que tratan con los mismos objetos de negocio.
  • Si luego queremos llamar a negocio desde otro sitio que no sea nuestra aplicación web (por ejemplo si montamos un servicio web para acceder a la misma lógica), tendremos que repetir estas validaciones en el servicio web.

Es decir, estamos rompiendo el principio DRY (Don’t repeat yourself – no te repitas), ya que nos vemos escribiendo las mismas validaciones una y otra vez.

Hibernate Validator (http://www.hibernate.org/412.html) pretende resolver este problema, de forma que definiremos una única vez las validaciones en nuestros objetos de negocio (en nuestros POJOS), e invocaremos esas validaciones desde el punto que nos
interese.

Principales características de Hibernate Validator:

  • Definimos las las validaciones muy fácilmente con anotaciones (es posible anotar tanto los atributos como los getters).
  • Trae un conjunto predefinido de validaciones típicas, conjunto que podemos extender fácilmente con nuestras propias validaciones.
  • El sistema soporta internacionalización: Ya trae mensajes de error traducidos a diez idiomas. Estos mensajes los podemos cambiar fácilmente, simplemente escribiendo nuestro propio fichero de propiedades y sobreescribiendo los mensajes que nos interese.
  • Se integra directamente con Hibernate, y en general con cualquier OR Mapping, de forma que antes de hacer una inserción o actualización se validarán los objetos.
  • Si usamos Hibernate, las validaciones que indiquemos se tendrán en cuenta a la hora de generar el DDL (los scripts de creación de la base de datos).

2. Entorno

El tutorial está escrito usando el siguiente entorno:

  • Hardware: Portátil Asus G1 (Core 2 Duo a 2.1 GHz, 2048 MB RAM, 120 GB HD).
  • Nvidia GEFORCE GO 7700
  • Sistema Operativo: GNU / Linux, Debian (unstable), Kernel 2.6.24, KDE 3.5
  • Java Sun 1.6.0_06
  • Hibernate 3.2.6.ga
  • Hibernate Validator 3.0.0 GA
  • JUnit 4.4


3. Configuración del entorno de desarrollo

La configuración del entorno, como siempre, la vamos a hacer con Maven. De esta forma resulta tan sencillo como añadir a nuestro pom.xml las siguientes líneas:

        ...
        <repositories>
                ...
                <repository>
                        <id>repository.jboss.org</id>
                        <name>JBoss Maven Repository</name>
                        <url>http://repository.jboss.org/maven2</url>
                        <layout>default</layout>
                </repository>
                ...
        </repositories>

        <dependencies>
                ...
                <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-validator</artifactId>
                        <version>3.0.0.GA</version>
                </dependency>
                ...
        <dependencies>
        ...

4. Validaciones predefinidas

Para ver las validaciones que Hibernate Validator trae «out of the box», lo mejor es ir diréctamente a la documentación:
http://www.hibernate.org/hib_docs/validator/reference/en/html/validator-defineconstraints.html#validator-defineconstraints-builtin

5. Añadiendo validaciones a nuestro POJO

Ahora vamos a crear un POJO y le pondremos un par de validaciones:

@Entity
public class Book {

        @Id
        @GeneratedValue
        private Integer id;

        @NotEmpty
        private String title;

        private String summary;

        @Past
        @Temporal(TemporalType.TIMESTAMP)
        private Date publicationDate;

        ...
        // Resto de constructores, métodos, getter y setters, etc
        ...

Vamos a comentar exclusivamente las anotaciones de Hiberante Validator:

  • Línea 8, @NotEmpty: Esta anotación indica que el titulo no pude ser null ni una cadena vacía.
  • Línea 13, @Past: Indica que la fecha tiene que estar en el pasado con respecto al momento actual.

6. Ejemplos de como se valida nuestro POJO

Vamos a ver un fragmento de código de un test donde se hacen varias comprobaciones sobre nuestro POJO:

@Test
public void testHibernateConstraints() {
        final Calendar calendar = Calendar.getInstance();
        calendar.set(3008, Calendar.FEBRUARY, 28);
        final Book book = new Book("", "lo mejor del ocultismo", calendar.getTime());
        try {
                dao.persist(book);
                Assert.fail();
        } catch (InvalidStateException e) {
                assertEquals(2, e.getInvalidValues().length);
        }

        ClassValidator<Book> validator = new ClassValidator<Book>(Book.class);

        InvalidValue[] invalidValues = validator.getInvalidValues(book);
        assertEquals(2, invalidValues.length);

        invalidValues = validator.getInvalidValues(book, "publicationDate");
        assertEquals(1, invalidValues.length);

        invalidValues = validator.getPotentialInvalidValues("publicationDate", calendar.getTime());
        assertEquals(1, invalidValues.length);

        invalidValues = validator.getPotentialInvalidValues("title", "");
        assertEquals(1, invalidValues.length);

}
  • Línea 5: Se ve como creamos un libro con un título vacío y con fecha en el futuro.
  • Línea 6 a 11: Persistimos el libro con Hibernate. Esto debería hacer saltar la validación, por lo que nunca deberíamos alcanzar la línea 8. Cuando fallan las validaciones se lanzará una excepción de tipo org.hibernate.validator.InvalidStateException
    (capturada en la línea 9). Esta excepción contienen toda la información sobre que es lo que ha fallado. Finalmente en la línea 10 se ve como se comprueba que hay dos valores inválidos: el título no puede ser vacío, y la fecha tiene que estar en el pasado.
  • Línea 13: Se ve como se crea un org.hibernate.validator.ClassValidator. Esta clase es la que utilizaremos para llamar al sistema de validaciones desde cualquier sitio que nos interese (no sería necesario si sólo se hacen las validaciones por Hibernate al insertar o actualizar un objeto en la base de datos).
  • Línea 15 en adelante: Se hacen varias comprobaciones. Cabe destacar especialmente el uso del método getPotetnialInvalidValues en las líneas 20 y 23. Este método lo que hace es validar si a un campo determinado se le puede aplicar un valor dado. Es decir, la validación es antes de que se aplique el valor (si os fijáis no se hace la validación con una instancia concreta de libro, simplemente se está preguntando si un determinado valor puede ser potencialmente peligroso.

JBoss Seam (http://www.jboss.com/products/seam) ya incluye la integración de este tipo de validaciones en nuestras páginas JSF
(http://docs.jboss.org/seam/3/validation/snapshot/reference/en-US/html_single/#validation-method-validation).
Hacer lo mismo en cualquier framework de JSF sería bastante sencillo. Simplemente habría que hacernos un pequeño componente que invocara a las validaciones del estilo mostrado en las líneas 20 y 23.

7. Recursos

Si queréis probar los ejemplos, en el tutorial sobre Hibernate Search
(http://www.adictosaltrabajo.com/tutoriales/tutoriales.php?pagina=hibernateSearch)
encontraréis un proyecto de ejemplo donde podréis integrar muy fácilmente el código que es han mostrado aquí.

8. Conclusiones

Siempre tenemos que intentar no repetir cosas, y mucho más si ya están inventadas. En este caso, Hibernate Validator puede ser una muy buena opción para gestionar las validaciones sobre nuestros POJOs.

Ya sabéis, en Autentia (www.autentia.com) siempre os recomendamos el uso de librerías y estándares. Siempre es mucho más barato (en coste y esfuerzo) integrar que desarrollar.
Por eso siempre es muy recomendable a la hora de empezar un proyecto, buscar a ver que podemos encontrar que nos haga la vida un poco más fácil.

9. Sobre el autor

Alejandro Pérez García, Ingeniero en Informática (especialidad de Ingeniería del Software)

Socio fundador de Autentia (Formación, Consultoría, Desarrollo de sistemas transaccionales)

mailto:alejandropg@autentia.com

Autentia Real Business Solutions S.L. – «Soporte a Desarrollo»

http://www.autentia.com

 

Alejandro es socio fundador de Autentia y nuestro experto en Java EE, Linux y optimización de aplicaciones empresariales. Ingeniero en Informática y Certified ScrumMaster. Seguir @alejandropgarci Si te gusta lo que ves, puedes contratarle para darte ayuda con soporte experto, impartir cursos presenciales en tu empresa o para que realicemos tus proyectos como factoría (Madrid). Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación.

1 COMENTARIO

  1. Hola,
    Coincido con la apreciación de Alberto, es más, para nuestro proyecto ese detalle es clave, si no hay manera de desligar el lanzamiento de las validaciones de las operaciones de persistencia, no nos va a interesar emplear esto. Creo que no debería ser obligado que una operación de persistencia lance validaciones, la spec JSR 303 obviamente no dice nada de eso.
    Saludos!

DEJA UNA RESPUESTA

Por favor ingrese su comentario!

He leído y acepto la política de privacidad

Por favor ingrese su nombre aquí

Información básica acerca de la protección de datos

  • Responsable:
  • Finalidad:
  • Legitimación:
  • Destinatarios:
  • Derechos:
  • Más información: Puedes ampliar información acerca de la protección de datos en el siguiente enlace:política de privacidad