Hibernate ist in der Java-Welt als Persistenzlösung längst zu einer festen Größe geworden. Mit Hibernate Tools möchte JBoss jetzt den Hibernate-Entwickler bei seiner Arbeit unterstützen. Eclipse-Plug-ins und IDE-unabhängige Ant Tasks erleichtern die Konfiguration und ermöglichen Reverse Engineering. Anhand eines einfachen Beispielszenarios stellen wir die neuen Tools und deren Bedienung Schritt für Schritt vor.
Wie bei vielen anderen Frameworks auch gibt es bei Hibernate einige Ansatzpunkte, den Entwickler mit Tools zu unterstützen. Ein gutes Beispiel hierfür ist das objektrelationale Mapping, bei dem Klassen und deren Beziehungen zueinander auf relationale Tabellen abgebildet werden. Das Kernprodukt Hibernate realisiert dies mit Mapping-Dateien im XML-Format, die vom Entwickler zu erstellen sind. Die Unterstützung, die Hibernate Tools [1] hier bieten kann, ist zum einen Code-Ergänzung und -Validierung und zum anderen Generierung von Mapping-Dateien aus dem Datenbank-Schema. Darüber hinaus bieten die Tools zum Beispiel Wizards für das Erstellen neuer Konfigurationsdateien und einen Editor für das direkte Ausführen von HQL-Befehlen.
Installation
Für Eclipse-Nutzer ist es wahrscheinlich am komfortabelsten, Hibernate Tools über den Update Manager zu installieren, um spätere Aktualisierung der Software zu vereinfachen. Alternativ gibt es auf der Website auch einen Download in Form eines ZIP-Archivs. Bleiben wir aber zunächst bei Eclipse und den Erweiterungen, die Hibernate Tools hier bietet. Der Update Manager wird über den Menüpfad Help | Software updates | Find and install aufgerufen. In der ersten Seite des erschienenen Wizards selektiert man Search for new updates to install und geht mit Next zur zweiten Seite. Hier kann man mit dem Button New Remote Site den URL der Plugin Update Site eintragen (download.jboss.org/jbosside/updates/stable) und ihr einen beliebigen Namen geben. Nachdem die Site hinzugefügt wurde, sollte man sicherstellen, dass nur diese selektiert ist, bevor man Finish drückt, um nach den verfügbaren Features zu suchen. Die Site bietet auch andere Features des JBoss DIE-Projektes, aber "Hibernate Tools" kann an dieser Stelle separat ausgewählt werden (Abb. 1). Nachdem man Next gedrückt hat, muss man noch die Lizenzvereinbarungen bestätigen und die Feature-Auswahl überprüfen (hier sollte nur "Hibernate Tools" erscheinen). Drückt man schließlich Finish, startet der Download und Hibernate Tools wird installiert. Nach einem Neustart von Eclipse stehen die neuen Tools zur Verfügung.
Anmerkung zur Umgebung
Für diesen Artikel kamen Java 5 Update 6, Hibernate 3.1.2, Hibernate Tools 3.1.0 beta4, und Eclipse 3.1.2 zum Einsatz. Die finale Version von Hibernate Tools steht bei Erscheinen des Artikels eventuell bereits zur Verfügung. Als Datenbank fand HSQLDB in der Version 1.8.0.2 Verwendung. HSQLDB wurde unter anderem in OpenOffice 2.0 verwendet und steht unter hsqldb.org zur Verfügung. Selbstverständlich können aber auch andere, von Hibernate unterstützte Datenbanken genutzt werden.
Eine Anmerkung für Anwender von WTP (Web Tools Platform): Hibernate Tools installiert in der vorgestellten Version Teile des WTP 1.0-Projektes. Sollte es hier zu Konflikten kommen, wird in der Dokumentation vorgeschlagen, mit einer neuen Eclipse-Installation zu starten, Hibernate Tools und danach das komplette WTP 1.0 zu installieren. Ein Blick in die aktuelle Dokumentation ist an dieser Stelle sicher nicht verkehrt.
Das Beispielszenario steht als Download zur Verfügung [2] bzw. finden Sie auf der CD. Hierin enthalten sind sämtliche Projektfiles und das SQL-Skript zur Erstellung des Datenbank-Schemas inklusive der Testdaten.
Um die Funktionen zu veranschaulichen, orientieren wir uns an einem Beispielszenario eines vereinfachten Bestellsystems. Dabei gehen wir von einer bereits bestehenden Datenbank aus, die Kunden, Produkte und Bestellungen enthält (Abb. 2). Für interessierte Leser steht das Szenario auch als Download zur Verfügung (siehe Kasten "Anmerkung zur Umgebung").
Fangen wir damit an, ein neues Java-Projekt in Eclipse mit dem Wizard zum Anlegen neuer Ressourcen (Ctrl + N) zu erstellen. Nachdem das Projekt angelegt ist, rufen wir den Wizard erneut auf und wählen an dieser Stelle
Hibernate Configuration File (cfg.xml)
aus. Auf der ersten Wizard-Seite muss zunächst ein Dateiname bestimmt werden. Wichtig ist, dass diese Datei später im Classpath verfügbar ist, also zum Beispiel in einem Source Folder liegt. Der voreingestellte Name
hibernate.cfg.xml
kann übernommen werden. Mit der nächsten Wizard-Seite (Abb. 3) können wir grundlegende Einstellungen treffen, die wir jetzt näher betrachten.
Das Feld
Session factory name
wird nur in einer JNDI-Umgebung benötigt und gibt dann den JNDI-Namen an, unter dem die
SessionFactory
abgelegt wird. Für unsere Umgebung lassen wir das Feld leer. Interessanter sind der Datenbank-Dialekt und die JDBC-Treiberklasse, die man in den nächsten zwei Feldern auswählen muss. In unserem Beispiel verwenden wir HSQL und die vom Tool hierfür vorgeschlagenen Treiberklasse
org.hsqldb.jdbcDriver
. Der URL für die JDBC-Datenbank-Verbindung muss im nächsten Feld angegeben werden. Soll ein bestimmtes Datenbank-Schema verwendet werden, gibt man es bei "Default Schema" an. Für die Hibernate-Grundkonfiguration fehlen jetzt noch der Datenbank Benutzer und das Passwort. Da wir aber gleich im Anschluss die Hibernate Console konfigurieren werden, aktivieren wir noch die entsprechende Checkbox und drücken Next. Die Hibernate Console ist ein zentraler Bestandteil des Hibernate Tools GUI, wie wir später sehen werden. Das eben erstellte Hibernate-Konfigurations-File ist bereits in der Hibernate Console Configuration (Abb. 4) eingetragen, sodass wir an dieser Stelle nur noch einen Namen vergeben und den Klassenpfad ergänzen müssen. Beim Klassenpfad ist zu beachten, dass er unabhängig von der Projekteinstellung ist. Folglich müssen hier der Klassenpfad des Projektes und die Treiberklassen für JDBC noch mal eingetragen werden. Vergisst man diesen Punkt, werden Fehlermeldungen nicht lange auf sich warten lassen.
Nachdem die Hibernate Console konfiguriert ist, öffnen wir die gleichnamige Eclipse-Perspektive mit dem entsprechenden Button oder dem Menupunkt Window | Open Perspective | Other.... Diese Perspektive besteht aus einigen Hibernate-spezifischen Views. Zentrale View ist "Hibernate Configurations", das in einer Baumstruktur auch unsere soeben angelegte Konfiguration darstellt. Bevor wir weitermachen, können wir mit dieser View testen, ob die Datenbank-Verbindung aufgebaut werden kann. Dazu öffnen wir den Baum bis zum Pfad Konfigurationsdatei | Database | Schema. Hier sollten dann die in der Datenbank verwendeten Tabellennamen sichtbar sein, wenn soweit alles geklappt hat.
Reverse Engineering
Kommen wir nun zur Hauptanwendung von Hibernate Tools: Reverse Engineering. Im typischen Projektverlauf existiert das Datenbank-Schema meist vor Java-Applikationen beziehungsweise, bevor Java-Entwickler ein bestehendes System in einer Persistenzschicht abbilden. Werden dabei O/R-Mapping-Frameworks wie Hibernate eingesetzt, folgt der Aufbau der Persistenzschicht meist einem wiederkehrenden Schema. Oft werden Tabellen in Klassen umgesetzt und dabei die Spalten mehr oder weniger 1 : 1 als Properties abgebildet (Daten-Beans). Dieser Schritt lässt sich mit Reverse-Engineering-Funktionen automatisieren, was besonders in der Anfangsphase von Projekten zu enormen Zeiteinsparungen führen kann. Dazu werden Meta-Informationen über die Datenbank mithilfe der JDBC-Schnittstelle abgerufen. Auf dessen Grundlage generiert Hibernate Tools weitere Ressourcen, wie beispielsweise Java-Datenklassen, Hibernate-Mapping-Dateien und DAO-Klassen. Entwickler werden sich vor allem darüber freuen, dass damit das langwierige Erstellen der Daten-Beans und deren Mapping entfallen. Dieser Mechanismus kann zudem konfiguriert werden, um individuellen Anforderungen bis zu einem gewissen Grad entgegenzukommen.
Das Aufrufen des Reverse Engineering verläuft ähnlich wie die Ausführung von Java-Programmen in Eclipse. Abbildung 5 zeigt das entsprechende Symbol mit dem Hibernate-Logo in der Taskleiste beziehungsweise dessen Kontextmenü. Wählen wir hier "Hibernate Code Generation..." öffnet sich ein Fenster für das Verwalten der verschiedenen Konfigurationen (Abb. 6).
Zunächst muss hier eine neue Konfiguration erstellt werden, was wir mit dem Button New im linken Bereich einleiten. Die Konfiguration muss zunächst benannt und einer Console Konfiguration zugeordnet werden. Das Feld "Output Directory" gibt das Ausgabeverzeichnis für die Codegenerierung an. Bei Java- und Mapping-Dateien entspricht dieser Pfad oft dem Quellverzeichnis des Java-Projektes. Nach Anwahl der Checkbox "Reverse engineer from JDBC Connection" können wir ein Java-Package angeben, in das der Code generiert werden soll. Die Einstellung "Generate basic typed ids" können wir aktiviert lassen. Sie besagt, dass Primary-Key-Spalten auf primitive Java-Datentypen (
int
,
long
etc.) abgebildet werden. Von der Möglichkeit, eigene Templates für die Generierung einzusetzen ("Use custom temlates"), werden wir keinen Gebrauch machen und lassen deshalb die Checkbox deaktiviert. Jetzt müssen wir nur noch auswählen, welche Ressourcen generiert werden sollen, und gehen hierfür zum Tab "Exporters". Für unser Beispiel aktivieren wir "Generate domain code (.java)", "Generate mappings (hbx.xml)" und "Generate hibernate configuration (hibernate.cfg.hbx)". Damit haben wir bereits alle Einstellungen getroffen und können mit Run die Generierung starten. Das Ergebnis kann im Package Explorer überprüft werden. In unserem Beispiel sollten hier für die Tabellen
KUNDE
,
PRODUKT
,
BESTELLUNG
und
BESTELLUNG_PRODUKT
die Java-Klassen
Kunde
,
Produkt
,
Bestellung
und
BestellungProdukt
mit jeweils einer Mapping-Datei erscheinen (Abb. 7). Zusätzlich wurde die Konfigurationsdatei
hibernate.cfg.hbx
um die Einträge der neuen Mapping-Dateien ergänzt.
An dieser Stelle könnten wir bereits eine Hibernate-Anwendung schreiben, welche über die soeben erzeugten Klassen auf die Datenbank zugreift. Zur Veranschaulichung ist das "HQL Scratchpad" jedoch besser geeignet, da damit Anfragen direkt ausgeführt werden können. Erreichbar ist es im Kontextmenu unserer Hibernate-Console-Konfiguration. Als Beispiel geben wir hier eine Abfrage ein, die alle Kunden mit mindestens einer unbezahlten Bestellung selektiert:
select k from Kunde k, Bestellung b
where b.kunde=k and b.bezahlt='N'
Neben dieser Abfrage zeigt Abbildung 8 weitere verwandte Views. Der "Hibernate Dynamic Query Translator" zeigt die SQL-Abfrage an, mit der Hibernate intern die Datenbank anspricht. Diese SQL-Abfrage kann beim Debugging hilfreich sein und könnte auch direkt in einem SQL-Tool ausgeführt werden. Die nächste View, "Hibernate Query Result", stellt die Ergebnisliste der HQL-Abfrage in Form von Java-Objekten dar. Die Darstellung greift dabei auf die
toString
-Methode zurück, die selbstverständlich überschrieben werden kann. Selektiert man ein Ergebnisobjekt, werden dessen Details in der View "Properties" dargestellt. In der Abbildung sehen wir beispielsweise, dass Erika Mustermann ihre Bestellung über fünf Headsets noch nicht bezahlt hat.
Es ist wahrscheinlich nicht überraschend, dass die automatische Codegenerierung noch Verbesserungspotenzial hat. Schauen wir uns zum Beispiel die generierte Klasse
Bestellung
an, stellen wir fest, dass das Property
bezahlt
den Typ
Character
hat. In der Datenbank wurde das Bezahl-Flag als
CHAR
umgesetzt, welches die Werte "Y" oder "N" annehmen kann. Auf der Java-Seite bietet sich der Typ
boolean
(oder auch Boolean) anstelle von
Character
an, um die Eigenschaft fachlich besser zu repräsentieren. Der "Hibernate Reverse engineering editor" erlaubt derartige Anpassungen. Zunächst müssen wir hierfür eine neue
reveng.xml
-Datei erstellen, die Zusatzinformationen für das Reverse Engineering enthält. Dazu öffnen wir wieder den New Wizard (Ctrl + N), wählen hier "Hibernate Reverse Engineering File (reveng.xml)" aus und drücken Next. Im folgenden Speicherdialog kann ein beliebiges Verzeichnis gewählt werden, da die Datei nicht im Classpath liegen muss. Jetzt können wir den Wizard mit Finish bereits abschließen und gelangen dann zum eigentlichen Reverse Engineering Editor, der sich auf mehre Tabs aufteilt. Im Tab "Overview" selektieren wir unsere Hibernate-Console-Konfiguration, um damit indirekt die Verbindungsdaten für die Datenbank zu spezifizieren. Im Tab "Table & Columns" drücken wir den Button Add und selektieren im erscheinenden Dialog die Spalte
BEZAHLT
der Tabelle
BESTELLUNG
. Jetzt können wir im rechten Bereich des Editors Anpassungen machen (Abb. 9). In unserem Beispiel können wir
yes_no
im Feld "Hibernate Type" angeben. Damit werden beim Reverse Engineering für diese Spalte das Hibernate Mapping angepasst und auf der Java-Seite der Typ Boolean verwendet. Die Entscheidung, ob das Reverse Engineering primitive Java-Typen oder deren Wrapper-Typen erzeugt, ist übrigens abhängig von der Spaltendefinition in der Datenbank. "NOT NULL"-Spalten werden als primitive Datentyp erzeugt. Bei der Version 3.1 beta4 ist jedoch noch anzumerken, dass diese Regel beim Typ
yes_no
noch nicht korrekt umgesetzt wurde und immer den Typ Boolean erzeugt.
Trotz der GUI-Unterstützung wird man bei größeren Projekten noch kaum komplett um das manuelle Editieren der Hibernate-Konfigurations- bzw. Mapping-Dateien herumkommen. Zum einen wird es bereits vorhandene Mappings geben, die man weiterbenutzen möchte, und zum anderen kann das Reverse Engineering verständlicherweise nicht alle erdenklichen Wünsche abdecken. So ist es auch denkbar, zuerst bestimmte Ressourcen einmalig zu generieren und sie danach auf Textebene anzupassen und weiter zu pflegen. Hierfür liefert Hibernate Tools den XML-Editor aus dem WTP-Projekt mit. Wie man es von DTD/Schema-Validierungen kennt, sind auch hier Prüfungen, Codeergänzungen und Hilfefunktionen verfügbar. Möchte man dann beim Reverse Engineering nur noch bestimmte Ressourcen generieren und somit vermeiden, dass andere überschrieben werden, erlaubt das Hibernate Tools GUI das Setzen von Filtern. Erreichbar ist diese Funktion im "Hibernate Reverse engineering editor" im Tab "Table filters".
Eher als grafische Spielerei und Ausblick auf spätere Versionen sind die Views "Hibernate Entity Model" (Abb. 10) und "Hibernate Relational Model" zu sehen. Hier werden die entsprechenden Modelle visualisiert, welche aber nicht mit Funktionen verknüpft sind. Damit haben wir einige grundsätzliche Funktionen des GUI kennen gelernt und wenden uns nun den Ant-Funktionalitäten zu. Weiterführende Informationen zum GUI, wie beispielsweise weitere Einstellungsmöglichkeiten für das Reverse Engineering, findet man in der Referenzdokumentation.
Ant Task
Hibernate Tools bietet Ant-Funktionen, die vollständig unabhängig von Eclipse sind. Damit wird eine Integration der Tools in den individuellen Build-Prozess möglich. Analog zu den Möglichkeiten des GUI erlauben die Ant-Funktionen anhand von verschieden Konfigurationen das Generieren unterschiedlicher Ressourcen. Zurzeit können Datenbank-DDLs, Java-Code, Hibernate-Konfigurations- und Mapping-Dateien, HTML sowie generische Templates erzeugt werden. Letztere finden beispielsweise für die Generierung von JBoss Seam-Bausteinen Verwendung. Als Template Engine wird Hibernate Tools in der finalen Version übrigens FreeMarker [3] verwenden und damit Velocity ablösen, das bis zur Version 3.1 beta4 eingesetzt wurde. Bei der GUI-basierten Variante des Reverse Engineering war unsere Datenquelle eine JDBC-Verbindung. Der Ant Task ist in dieser Beziehung flexibler, da hier Datenquellen als Konfigurationen abstrahiert sind. Als Konfiguration können dabei JDBC-Verbindungen, Hibernate-Mapping-Dateien oder Java-Klassen mit Annotations dienen. Prinzipiell lässt sich aus jeder Konfigurationsart auch jede Ressourcenart erzeugen.
Im Folgenden greifen wir die beispielhafte Vorgehensweise wieder auf und erzeugen aus dem Datenbank-Schema diesmal EJB 3.0-Java-Klassen mit Annotations und eine HTML-Dokumentation. Danach drehen wir die Vorgehensweise um, indem wir die Java-Klassen zum führenden System machen und das Datenbank-Schema anhand der Annotations aktualisieren. Zunächst muss für die Nutzung der Ant-Funktionalitäten ein neuer Task im Buildfile mit
taskdef
definiert werden. Dafür muss der Classpath bei der Ausführung von Ant erweitert werden. Das kann zum Beispiel mit dem zusätzlichen Attribut
classpath
oder dem Eclipse GUI (Tab "Classpath" unter "External Tools") gemacht werden. Benötigt werden die JARs der Hibernate Tools (im Eclipse-Verzeichnis unterhalb von
plugins/org.hibernate.eclipse_X.Y.Z/lib/tools
), die Standard Hibernate JARs und die Klassen des JDBC-Treibers. Nach der Definition können wir diesen Task benutzen und innerhalb des
hibernatetool
Tags die Konfiguration setzen und Generierungsfunktionen aufrufen. Das Listing 1 zeigt das Buildfile für unser Beispielszenario. Im Target
jdbc2ejb
wird eine
jdbcconfiguration
verwendet, welche die JDBC-Verbindungsdaten aus der die Datei
src/hibernate.cfg.xml
bezieht. Zusätzlich werden die bereits erstellte
hibernate.reveng.xml
-Datei und ein Package-Name angegeben. Nach der Konfiguration können verschiedene Tags zur Generierung von Ressourcen verwendet werden. So erzeugen wir mit
hbm2java
Java-Code in das Verzeichnis
ejb3-src
. Da wir EJB 3.0-Code erzeugen möchten, setzen wir noch zusätzlich die Attribute
ejb3
und
jdk5
auf
true
. In dasselbe Zielverzeichnis erzeugen wir mit dem Befehl
hbm2cfgxml
ein neues Konfigurationsfile für Hibernate, welches die nötigen Änderungen für den Einsatz von EJB 3.0 enthält. Schließlich erzeugen wir mit
hbm2doc
eine HTML-Dokumentation, die das Datenbank-Schema mit seinen Tabellen und Spalten beschreibt.
Neben der Erzeugung von EJB 3.0-Code kann man selbstverständlich auch weiterhin Java 1.4-Code erzeugen. Dazu lässt man die
ejb3-
und
jdk5
-Attribute weg und ruft zusätzlich noch den Befehl
hbm2hbmxml
für die Generierung der Mapping-Dateien auf. Bleiben wir aber beim EJB 3.0-Ansatz, der uns Mapping-Dateien erspart und uns erlaubt, das Mapping direkt im Java-Quelltext mithilfe von Annotations festzulegen. Bislang wird dies nicht nativ von Hibernate unterstützt, sodass die Erweiterung Hibernate Annotations [4] benötigt wird. Die dazugehörigen JARs müssen bei der Verwendung im Klassenpfad verfügbar sein, was auch für den Ant Task gilt. Als letzte Aufgabe werden wir die generierte EJB 3.0-Klasse
Kunde
um das Property
adresse
erweitern und dieses in der Datenbank widerspiegeln. In der Java-Klasse erstellen wir zunächst das neue Property mit getter- und setter-Methoden. Dann ergänzen wir es um folgende Annotation analog zum Property
name
:
Abschließend betrachtet setzt Hibernate Tools in der aktuellen Version den Schwerpunkt eindeutig auf Reverse Engineering. Aus der Roadmap geht aber hervor, dass für zukünftige Versionen unter anderem spezielle Editoren für Konfigurations- und Mapping-Dateien sowie weitere Reverse-Engineering-Optionen geplant sind. Zwar merkt man der Software noch an einigen Stellen an, dass es sich noch um eine Beta-Version im frühen Stadium handelt, aber vor allem das Reverse Engineering macht einen Einsatz schon jetzt lohnenswert. Hibernate Tools ist nicht das einzige Projekt seiner Art. Weitere interessante, aber zurzeit weniger gepflegte Open-Source-Projekte sind Hibernate Synchronizer, Middlegen oder auch XDoclet und dessen Hibernate-spezifische Tags. Daneben gibt es auch vielversprechende kommerzielle Ansätze. Beispielsweise bietet das auf Eclipse basierende BEA Workshop Studio viele visuelle Editoren, Wizards und auch konfigurierbares Reverse Engineering. Hibero ist ein Plug-in für IntelliJ IDEA für Codeergänzung, aber verzichtet bislang von auf unterstützende GUIs oder Reverse Engineering. Erwähnenswert ist auch noch die Hibernate-Funktionalität von MyEclipse Enterprise Workbench - sie basiert auf einer älteren Version von Hibernate Tools. Mehr oder wenig unabhängig von Hibernate gibt es auch schon einige Tools für den kommenden Standard EJB 3.0 wie zum Beispiel Dali von Eclipse (hier beteiligen sich auch die JBoss IDE-Entwickler) oder Oracles JDeveloper. Insgesamt wird deutlich, dass zurzeit einige interessante Entwicklungen in diesem Bereich stattfinden. Wenn Sie Hibernate Tools jetzt ausprobieren möchten, empfiehlt es sich, anhand eines kleinen Projekts die Funktionalität selbst nachzuvollziehen. Als Vorlage kann dafür auch das herunterladbare Beispielszenario [2] dienen. Markus Junginger beschäftigt sich seit 1998 mit Java und ist Consultant für Java EE und NetWeaver bei Unilog Avinci. Kontakt: markus.junginger@unilog.de.