Día movidito con Hibernate

Ayer en el trabajo fue un día bastante movidito con el tema de Hibernate.

Me llevé de casa el build.xml y todos los jar necesarios para hacer allí una prueba, pero esta vez con una base de datos de verdad, con varias tablas "reales", en vez de mi tabla "Persona" de tres campos.

Por supuesto, como soy un cotilla y me gusta contarlo todo -valga este blog como prueba-, según iba haciendo experimentos, se lo iba contando a la gente. Al final había allí tres más conmigo haciendo pruebas. Emocionados con el tema, salí a las tantas.

Ahí van las pruebas y resultados que obtuve:

Elegí entre las las bases de datos que tenemos, una de tamaño medio en cuanto a número de tablas para hacer las pruebas. Debe tener entre 20 y 30 tablas -no las he contado- y muchas relaciones raras entre ellas.

Configuré el build.xml con los datos de la conexión y la primera parte, la de obtener los hbm.xml a partir de la base de datos fue como la seda. Sin ningún problema me saco los 20 ó 30 ficheros hbm.xml, uno por tabla.

Llegó el momento de generar los beans de java. Fallo estrepitoso. Daba un error bastante al principio y no generaba nada de nada. Después de un par de horas de pelearme con él, dí con el problema, increible donde los haya. Resulta que los ficheros hbm.xml llevan arriba, en la tercera o cuarta línea, una referencia al fichero dtd tal que así http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd . Hibernate-tool, cuando revisa ese fichero, intenta acceder a internet para coger ese fichero .dtd y poder comprobar si el XML es correcto o no. Pues bien, resulta que trabajamos a través de proxy que requiere usuario y password. Hibernate-tool no puede acceder a dicho fichero dtd y falla. Como no tenía ganas de empezar a ver si se puede configurar hibernate-tool para que trabaje a través de proxy, lo que hice fue bajarme todos los dtd que se mencionan en los ficheros .hbm.xml, e incluso los que se mencionan en el mismo dtd y ponerlos en mi ordenador -en total tres ficheros-. Luego, cambie todos los http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd por file:///d:/hibernate-mapping-2.0.dtd . Todo estupendo, generó los beans de java sin problemas aparentes.

La siguiente prueba, hacer el código java para consultar y sacar por pantalla la tabla principal de la base de datos.

Otro pequeño desastre. Al leer Hibernate sus ficheros .hbm.xml de configuración "casca". En casi todas las relaciones many-to-one me dice que hay un nombre de columna repetido y que debería ponerle insert="false" update="false". Así que nada, a mano, sin saber muy bien qué es lo que estoy haciendo, se lo pongo en los ficheros .hbm.xml en todos los sitios donde me va protestando el Hibernate al leer. Después de un rato -eran 20 ó 30 ficheros con varias relaciones en cada uno-, consigo que Hibernate lea la configuración y no "casque".

Pero, la siguiente en la frente. Al cargar la lista de beans asociados a la tabla principal -en el query()-, una excepción de un NullPointerException y/o un ClassCastException en una clave compuesta de una tabla de asociación que asocia un registro de la tabla principal con otro registro de la tabla principal. Ahí ya si me quedé bloqueado.

Hablando con el master del universo y de las bases de datos, me comenta que esa relación en esa tabla es válida, pero sí es cierto que es un poco extraña, ya que reutiliza las mismas claves primarias como …. -aquí un rollo técnico de BD que se me escapa totalmente-. En fin, que para probar, me quita esa relación. Vuelvo a repetir todo el proceso y todo correcto y funcionando.

¿Cual es el plan para hoy?. Pues aunque las que he encontrado están en versión alpha, voy a probar a realizar el proceso con hibernate-tool 3 en vez de con la versión 2.1, a ver si es capaz de tragar directamente con todo, sin necesidad de hacer cambios.

Al final, como dijo uno de mis compañeros, me da que esto de Hibernate va a servir para bases de datos de estructuras sencillas, sin complicaciones -no quiero decir pocas tablas ni pocos datos, sino simplemente que no tengan "virguerías" en las relaciones-. Supongo que tendré que hablar con el responsable de las bases de datos para que las futuras bases de datos que nos hagan no lleven demasiadas cosas raras.
 

Por fin, generados los beans con Hibernate

Por fín. Me ha costado un horror, pero lo he conseguido. A partir de la base de datos, he conseguido generar los ficheros hbm.xml de hibernate y a partir de ellos, el código java de los beans.

Al final tuve que hacerlo con ant y aún así ha costado. En ningún sitio te pone claramente el proceso y los jar necesarios están escondidos por el internet.

Aunque haré un pequeño ejemplo más detallado en la Chuwiki cuando me aclare qué es exactamente lo que he hecho, aquí va un pequeño avance.

Generar los hbm.xml a partir de la base de datos

Para generar esto, además de algunos .jar que se nos colarán, necesitamos los jar de hibernate core y los de middlegen. De este último hay una versión 3.x, pero creo que está en un estado muy "alpha".

Los .jar que se nos pueden colar son, por supuesto, el driver java de la base de datos que usemos y a mí me ha hecho falta un velocity-x.x.jar. Hay un pequeño truco para sacar todos estos jars raros que no vienen en ningún lado. Dentro de middlegen, hay un directorio samples con un subdirectorio lib. Ahí están todos los que necesitamos. Es curioso que esta gente no ponga todos los jar necesarios en la herramienta, pero sí los ponga en el ejemplo.

Una vez que tenemos todo, hay que hacerse un build.xml similar al que aparece en la página de middlegen, el primero que aparece de ejemplo. Por supuesto, luego hay que andar arreglándolo para nuestros paths concretos. Una vez arreglado todo, se ejecuta ant. Este se conecta a la base de datos y nos crea los ficheros hbm.xml, uno por tabla.

Generar los fuentes de los bean java a partir de los hbm.xml

Para esto segundo, necesitamos además dos misteriosos y escondidos jars: hibernate-tools.jar y freemarker.jar. Estos son los que más "por el …" me han dado. No había manera de econtrarlos por ningún sitio.

El sitio que aconseja en la página es descargarse hibernatetools, en su versión plugin para eclipse. Una vez desempaquetado el plugin de eclipse, nos vamos al directorio plugins/org.hibernate.eclipse_3.2.0.cr1/lib/tools/ y listo, ahí tenemos las famosas hibernate-tools.jar tan necesarias.

Por supuesto, también nos vale el truco de antes. Nos vamos al directorio samples/lib de middlegen y ahí también lo tenemos.

Finalmente, hay que hacerse otro build.xml -o juntarlo con el anterior- en el que he puesto esto -no recuerdo de dónde lo he sacado

<target name="hbm2java">
<taskdef name="hibernatetool"
    classname="org.hibernate.tool.ant.HibernateToolTask"
    classpathref="lib.class.path"/>
<hibernatetool destdir="path_donde_dejar_los_fuentes">
 <configuration>
   <fileset dir="path_donde_estan_los_hbm_xml">
    <include name="**/*.hbm.xml"/>
   </fileset>
 </configuration>
 <hbm2java/>
</hibernatetool>
</target>

y nada, funcionó. Me generó los beans java correspondientes a las tablas.

No sé yo Hibernate…

Pues nada, veo que Hibernate tiene muy buena pinta, si haces lo que él quiere.

Dicho de otra forma. Tú te generas tu fichero de configuración de hibernate, con él generas la base de datos -y los beans creo- y todo estupendo y maravilloso.

Pero, ¿qué pasa si ya tienes la base de datos creada de antes?. Nada más fácil, te haces el fichero de configuración de hibernate a mano y todo estupendo y maravilloso.

Pero, ¿qué pasa si la base de datos tiene mogollón de tablas con tropecientas columnas cada una?. Pues tampoco pasa nada, hay una cosa que se llama ddl2hbm que ya está obsoleta, pero que ha sido reemplazada por otra que se llama middlegen que hace justamente eso que quieres. Coge una base de datos y genera el fichero de configuración de hibernate. Todo estupendo y maravilloso.

Vaya. Veo que lo de middlegen está pensado para funcionar con ant. Ejecutarlo requiere que tengas ant, que sepas ant y que configures un build.xml con una decena de propiedades. A ver si encuentro algo más sencillo.

Middlegen también tiene un plugin para eclipse, el middlegenide. Tiene buena pinta. Lo instalo. Después de diez minutos -o media hora- de rebuscar por eclipse encuentro desde dónde lanzarlo: "file" -> "new" -> "other" -> "middlegen" … y con eso se supone que consigo… un build.xml de ant. Relleno los datos que me pide el formulario y obtengo un error de lo más descriptivo -ver foto-

error

Y con eso, claramente, sé sin lugar a dudas qué es lo que ha fallado. Acepto el error -pulso OK- y lo arreglo

Así que nada, a  buscar otra opción. Veo también que hay plugin de maven. Lástima, parece que es para maven 1 y yo tengo maven 2. No sé dónde demonios tengo que configurar los datos de conexión a base de datos, ya que el project.properties creo que no existe en maven 2. Tampoco tengo demasiadas ganas de abrir recursivamente una segunda investigación de dónde meter en maven2 el project.properties para configurar el plugin de maven de middlegen para ver cómo funciona este plugin con una base de datos…. Bufff.

Sigo investigando y me encuentro otro plugin de eclipse: HiberClipse. Este es mejor todavía. Ni suquiera he conseguido instalarlo. El "update manager" o como demonios se llame, se va a la URL que dice allí y no encuentra nada de nada para instalar.

En fin, me tendré que dedicar un par de horitas a recordar ant, configurar el dichoso build.xml a mano y rezar para que salga algo.

Jugando con Hibernate

Me he puesto a jugar un poco con Hibernate y me ha encantado, aunque también he empezado a odiar ciertas cosas.

Primero intenté crear un proyecto maven con hibernate, para obtener los jar de forma automática. Por ahí surgieron mis primeros poblemas. Encontré en el repositorio maven un groupId "hibernate" y otro "org.hibernate" y, por supuesto, en el primer intento me equivoqué.

En org.hibernate -el que al final usé- otra sorpresa. Los números de versión son raros porque llevan una letras detrás, por lo que ya no sabes qué bajarte. Si no hay letras, está claro, el último número, pero con letras…. Me decido por uno. Mis segundos problemas y comienzos del odio fue que no se bajó el jta.jar. Eso, hasta cierto punto es normal. El jta.jar es de sun y sun no permite que otros distribuyan sus jar. Hay que ir a la página de sun y bajárselo. Me voy a la página de sun … y jta.jar pertenece al paqute JEE. ¿Por qué me tengo que bajar JEE si sólo hago aplicaciones de escritorio?.

No obstante, intenté bajarme e instalar JEE … en linux. Error al desempaquetar el paquete porque me falta no sé qué ¿versión concreta, con números, de una librería de C++?. ¿Tengo que tener instalada una versión concreta de la librería C++ para desempaquetar JEE?. ¡¡ Paso de JEE !!. ¡A ver si al final tengo que recompilar el kernel!

Me fuí a la página de Hibernate y me bajé Hibernate core. Me costó un buen rato decidir qué bajaba. No conozco Hibernate, pero sí sé lo que quería: ¡No depender de JEE!. Tarea casi imposible. En cualquier sitio de Hibernate que te metas, por mucho J2SE que ponga en el enlace, empieza a mencionar EJBs y JBoss.

Bueno, ya he protestado bastante. No me gusta nada la página de Hibernate, no me parece clara y hay que darle demasiadas vueltas hasta encontrar lo que quieres. Vamos ahora con lo bueno.

Como dije, me bajé Hibernate core y ahí sí venía el jta.jar y por suerte, no venía el JEE. ¿Por qué sun deja distribuir a Hibernate su jta.jar y no deja a Maven?. Luego, un ojo a la documentación para seguirla y tratar de hacer algo.

Y ahí empecé a maravillarme de sus posibilidades.

Por un lado, según Hibernate hay tres formas de definir la base de datos. Podemos tener la base de datos en sí. Podemos hacer un fichero xml al estilo Hibernate en que se relacionen tablas de base de datos con beans de java y las columnas de las tablas con los atributos del bean. Y finalmente, podemos tener beans java con "annotations". Eso de las annotations no es más que poner encima de los atributos java cosas como @id, @column de forma que con esto indicamos qué es cada atributo del bean en la base de datos.

Primera maravilla. A partir de cualquiera de esas tres, Hibernate es capaz de generar las otras dos. Si yo escribo el fichero xml, Hibernate crea las tablas en base de datos y el código java de los beans. Si tengo la base de datos, Hibernate crea el fichero xml y los fuentes java de los beans. Y si tengo ya los beans hechos, con sus annotations, Hibernate crea las tablas de base de datos de y el fichero xml. Por supuesto, todo eso opcional. En mi caso, las tablas de datos en el trabajo están hechas. Sacaría de ellas el xml y los beans.

Por supuesto, permite relaciones entre beans/tablas de las típicas uno a uno, uno a muchos, muchos a muchos. En los beans java simplemente son atributos Hash, List o lo que sea y en las tablas incluso crea las tablas intermedias con los dos índices de las relaciones.

Unas peguillas: Lo de generar la base de datos a partir del xml, en el ejemplo que pone la documentación viene que se haga automático. Así que mi primera prueba se cargó la tabla de base de datos que tenía, con sus datos, y me la creo de cero. Ahí que tener cuidado con estas cosas. La otra peguilla es que para esto necesitas "Hibernate tools", pero entre que viene para usar con ant o como plugin de eclipse que no me ha funcionado de momento, pues de momento no soy capaz de hacer nada de eso -salvo cargarme la base de datos la primera prueba-. Es la primera herramienta que veo que dan la opción "destructiva" fácilmente accesible como ejemplo y las opciones "constructivas" escondidas entre scripts crípticos de ant.

Segunda maravilla. Una vez configurado todo, desde código java puedo obtener a través de Hibernate un bean correspondiente a un registro de una tabla. Pues bien, cualquier modificación en los datos que haga de ese bean en el código java, se refleja automáticamente en la base de datos. Cuando termine las modificaciones, puedo hacer un commit() o un rollback() para confirmar o cancelar los cambios. Con Hibernate, en un momento dado, podemos olvidarnos totalmente de que hay una base de datos detrás y de todas las sql, salvo, quizás, para la carga inicial de datos. Los beans son realmente persistentes en BD, sin necesidad de código separado para insertarlos o modificarlos en base de datos.

Seguiré investigando y jugando con el tema porque creo que sí que merece la pena usar una herramienta como esta. Me da "cosa" que esté tan "casada" con JEE y JBoss. También me dan las dudas de eficiencia luego en tiempo de ejecución, pero hasta que no se pruebe, no se sabe. En cualquier caso, sólo con que de una tabla de BD te saque el código java de los beans, ya merece la pena.