Enrique Viñé Lerma

Consultor tecnológico de desarrollo de proyectos informáticos.

Ingeniero Técnico en Informática por la Universidad Politécnica de Madrid.

Puedes encontrarme en Autentia: Ofrecemos servicios de soporte a desarrollo, factoría y formación

Somos expertos en Java/J2EE

Ver todos los tutoriales del autor

Fecha de publicación del tutorial: 2009-01-28

Tutorial visitado 11.212 veces Descargar en PDF
Eventos en Hibernate

Eventos en Hibernate (Parte II)

Índice de contenidos

  1. Introducción

  2. Entorno

  3. Reconfigurando la aplicación de ejemplo

  4. Un DAO nuevo

  5. Configuración de Hibernate

  6. Probar de nuevo la aplicación

  7. Configurar eventos

  8. Añadir nuestros propios oyentes

  9. Diferentes formas de gestionar los eventos

  10. Conclusiones

1. Introducción

Este tutorial es continuación del tutorial "Eventos en Hibernate (Parte I)". Aquí vamos a centrarnos en el uso de los eventos definidos en la especificación EJB3 gracias a Hibernate Entity Manager. Podemos asociar métodos de retrollamada a diferentes eventos de forma que se ejecuten de manera automática. Por ejemplo, esto es muy útil para calcular el valor de campos de nuestros objetos que no se persisten en la base de datos, pero se pueden calcular en función de otros; podemos asignar un método de retrollamada para que se ejecute al cargar la entidad y calcule el valor de dicho campo.

En este tutorial vamos a continuar con el ejemplo que vimos anteriormente, en el cual teníamos una entidad usuarios con un campo edad no persistido, que se calculará automáticamente a partir de la fecha de nacimiento.

2. Entorno

Para la realización de este tutorial se han utilizado las siguientes herramientas:

  • Hardware: Portátil Asus G50Vseries (Core Duo P8600 2.4GHz, 4GB RAM, 320 GB HD).

  • Sistema operativo: Windows Vista Ultimate.

  • Eclipse Ganymede 3.4.1, con el plugin Q (http://code.google.com/p/q4e) para Maven

  • JDK 1.6.0

  • Maven 2.0.9

  • MySql 5.1.30

  • Hibernate 3

3. Reconfigurando la aplicación de ejemplo

Para poder utilizar un EntityManager debemos añadir la siguiente dependencia al fichero pom.xml.

4. Un DAO nuevo

El Dao que habíamos utilizado en el ejemplo anterior no nos vale ahora, ya que utilizaba una Session de Hibernate para manejar nuestras entidades. Si queremos tener toda la potencia de las anotaciones EJB3 debemos utilizar un EntityManager, que es equivalente a Session pero amplía sus capacidades permitiéndonos utilizar toda la semántica de EJB3.

Es importante realizar las operaciones de persistencia dentro de una transacción para poder hacer COMMIT. De lo contrario por defecto se hará ROLLBACK y nuestras acciones no tendrán el efecto esperado. Nosotros mismos deberemos controlar en nuestro código la creación del EntityManager y el inicio y fin de las transacciones, ya que nuestra aplicación va a ejecutarse fuera de un contenedor J2EE.

5. Configuración de Hibernate

Para crear el EntityManager, hemos utilizado la clase Persistence, pasándole al método "createEntityManagerFactory" un nombre como parámetro. Este nombre identificará una unidad de persistencia en la que definiremos la configuración que será utilizada para crear el EntityManager. Este fichero se llamará "persistence.xml" y deberá ponerse dentro de la carpeta "META-INF", porque es allí donde lo buscará la EntityManagerFactory. El atributo name de la unidad de persistencia debe coincidir con el que le pasamos a la EntityManagerFactory.

El tipo de transacción se ha puesto como "RESOURCE_LOCAL". Esta es la única posibilidad que tenemos para un simple proyecto Java, pero si dispusiéramos de un contenedor J2EE podríamos utilizar "JTA", lo cual nos evitaría tener que iniciar por nosotros mismos las transacciones.

Una alternativa a poner la configuración de Hibernate en el fichero "persistence.xml" consiste en indicar un fichero de configuración de hibernate de donde cogerla (la línea que aparece comentada en el código anterior). Podemos incluso mezclar ambas configuraciones, pero en caso de conflicto siempre prevalecerá la que pongamos en el fichero "persistence.xml".

6. Probar de nuevo la aplicación

Ahora sólamente nos queda probar la aplicación que hemos rehecho, para ver si funciona como es debido. Para ello modificamos nuestras dos clases de prueba para que utilicen el nuevo Dao.

Aquí está el código modificado de nuestra clase PruebaInsercion.

Y aquí tenemos la clase PruebaListado, que utiliza también el nuevo Dao.

Si hemos seguido el tutorial anterior tendremos que borrar la tabla de nuestro esquema de base de datos, para comprobar que vuelve a crearse y a cargarse con datos correctos.

Ejecutamos primero la inserción y comprobamos que se han añadido correctamente los usuarios a nuestra base de datos:

Consulta de usuarios en la base de datos

Ahora ejecutamos la prueba de listado y observamos... ¡Vaya, esto me suena! Lo hemos vuelto a hacer, ¿no teníamos que capturar el evento?.

Listado de usuarios con edad igual a cero

7. Configurar eventos

Este es el apartado que más me gusta del tutorial, porque sólamente tenemos que escribir una palabra: @PostLoad. Esta anotación delante de nuestra función "calcularEdad" es todo lo que tenemos que hacer para que nuestra función sea llamada después de cargar los datos de la entidad. Deberemos también añadir el import necesario.

Si volvemos a ejecutar la función que lista los usuarios, obtendremos el resultado esperado:

Listado de usuarios con edades correctas

A continuación se muestran todas las anotaciones que pueden utilizarse para que los métodos de la entidad sean llamados de forma automática al producirse un evento en su ciclo de vida. Los métodos anotados de esta manera se llaman "Callback Methods" o métodos de retrollamada.

Podemos asignar varias anotaciones para un mismo método, y designar varios métodos de retrollamada en una misma entidad. Pero no podremos asignar dos métodos diferentes para el mismo evento.

Tipo Descripción Interfaz del oyente
@PrePersist Ejecutado antes de realizar la persistencia (INSERT) del objeto.  org.hibernate.event.PreInsertEventListener
@PreRemove Ejecutado antes de realizar el borrado (DELETE) del objeto.
org.hibernate.event.PreDeleteEventListener
@PostPersist Ejecutado después de realizar la persistencia del objeto.
org.hibernate.event.PostInsertEventListener
@PostRemove Ejecutado después de realizar el borrado del objeto. org.hibernate.event.PostDeleteEventListener
@PreUpdate Ejecutado antes de la actualización (UPDATE) del objeto.
org.hibernate.event.PreUpdateEventListener
@PostUpdate Ejecutado después de la actualización del objeto. org.hibernate.event.PostUpdateEventListener
@PostLoad Ejecutado después de la carga o refresco del objeto. org.hibernate.event.PostLoadEventListener

8. Añadir nuestros propios oyentes

La anotaciones anteriores asignan los oyentes predeterminados de Hibernate a los métodos de retrollamada. También podemos asignar nuestros propios oyentes anotando la clase con @EntityListeners. Podremos pasarle como parámetro nuestra clase oyente o un array de clases oyentes:

@EntityListeners(value=Oyente.class) ó @EntityListeners(value={Oyente1.class, Oyente2.class, ...})

Las clases oyentes asignadas de esta manera deberán implementar métodos para cada evento que quieran manejar, los cuales se marcarán con la anotación correspondiente. Estos métodos recibirán como parámetro una instancia de la entidad sobre la que ocurre el evento.

Vamos a implementar un oyente que rejuvenezca a nuestros usuarios, pero esta vez cambiando su fecha de nacimiento.

Para que se ejecute el oyente, tendremos que utilizar la anotación @EntityListeners en la entidad Usuario:

Si ejecutamos el listado, veremos la siguiente salida:

Lista de usuarios rejuvenecidos

Si nos fijamos en las sentencias update de Hibernate veremos que esto ha tenido un efecto secundario. Hemos cambiado la fecha de nacimiento de los usuarios en la base de datos. Recordemos que según la semántica de EJB3, si tenemos un objeto manejado por el gestor de persistencia no es necesario hacer persist, merge, update o nada parecido para guardar los cambios que hagamos al mismo. Nosotros modificamos el valor de los campos del objeto y el gestor de persistencia se encargará automáticamente de reflejar esos cambios en la base de datos. Así que... este nuevo lifting parece más duradero que el anterior ;)

9. Diferentes formas de gestionar los eventos

Tenemos diferentes maneras de conseguir que un método se ejecute al producirse un evento para una entidad. En caso de existir varios métodos a ejecutar, estos se ejecutarán en el orden siguiente:

  1. A través de la anotación @EntityListeners en la entidad o una superclase de la misma. Estos oyentes se ejecutarán en el orden en que se añadan al array "value". Es posible evitar que se ejecuten los oyentes definidos por la anotación @EntityListeners de las superclases utilizando la etiqueta @ExcludeSuperclassListeners en una entidad.
  2. Oyentes de las superclases de la entidad definidos en el fichero de configuración (primero la superclase de nivel superior).
  3. Oyentes de la propia entidad definidos en el fichero de configuración.
  4. Métodos de retrollamada (anotaciones @PostLoad...) para las superclases de la entidad (primero la de nivel superior).
  5. Métodos de retrollamada para la entidad.

Ya hemos visto cómo utilizar los métodos de retrollamada y también la anotación @EntityListeners. También podemos asignar los EntityListeners y los métodos de retrollamada por medio de un fichero de configuración xml. Deberemos indicar en nuestro "persistence.xml" el fichero de mapeo a utilizar:

A través del fichero de mapeo podemos asignar oyentes por defecto para todas las entidades y oyentes particulares para cada entidad e, incluso, definir los métodos de retrollamada de nuestra entidad sin utilizar las anotaciones. Por ejemplo, en el siguiente fichero xml hemos definido para la entidad Usuario el oyente EJB3LiftingUsuarioOyente y asociado el evento post-load al método calcularEdad.

Es importante destacar que no pueden definirse dos métodos de retrollamada diferentes para el mismo evento, por lo que deberemos eliminar las anotaciones @PostLoad de nuestra entidad Usuario y de nuestra clase EJB3LiftingUsuarioOyente.

10. Conclusiones

A la vista de los resultados de este tutorial, podemos extraer las siguientes conclusiones:

  • Un EntityManager nos permite utilizar Hibernate con la semántica definida por JPA para la especificación de EJB3.

  • Podemos mantener nuestra antigua configuración de Hibernate añadiendo una referencia a la misma en nuestro persistence.xml. A pesar de eso, podremos sobreescribir ciertas propiedades en el nuevo fichero de configuración.

  • Con el uso de las anotaciones de EJB3 es muy sencillo definir métodos de retrollamada para los eventos del ciclo de vida de nuestras entidades, y también es más sencillo crear nuestras propias clases oyente.

Y eso es todo por ahora. En el próximo tutorial de esta serie veremos una forma de utilizar las anotaciones de EJB3 para definir eventos de retrollamada utilizando sólamente la clase Session de Hibernate, es decir, sin utilizar un EntityManager.

Una vez más, desde Autentia esperamos que este tutorial os sea de ayuda si os encontráis en la necesidad de ejecutar eventos en Hibernate.

A continuación puedes evaluarlo:

Regístrate para evaluarlo

Por favor, vota +1 o compártelo si te pareció interesante

Share |
Anímate y coméntanos lo que pienses sobre este TUTORIAL: