Часто у программистов Hibernate возникает задача по первоначальной конфигурации XML-маппингов и созданию POJO-классов на основе схемы из существующей базы данных.
Несомненно, наилучшим способом решения проблемы, как в плане понимания структуры базы, так и в плане чистоты кода, будет описание классов и маппингов вручную.
Но когда схема базы приличного масштаба, то очень хочется этот процесс автоматизировать… Или хотя бы создать скелеты POJO-классов и XML-файлов, которые можно будет вручную скорректировать позже.
Для автоматизации процесса (и не только) существует пакет Hibernate Tools, позволяющий описать задачи для реверса схемы существующей БД в файлы сущностей Hibernate, используя возможности инструмента сборки Java приложений Ant.
В популярной среде разработки Eclipse и NetBeans существуют визарды, позволяющие упростить процесс конфигурирования Hibernate Tools, но мы их использовать не будем(я использую NetBeans, но встроенный Hibernate-визард разочаровал меня отсутствием гибкой конфигурации реверса, возможности визардов Eclipse я не исследовал, но предполагаю, что они не сильно отличаются от NetBeans'овых...). Итак, мы выбираем хардкорный путь генерации через Ant-скрипты.
Перед нами стоит задача сгенерировать скелеты POJO-классов и XML-маппинги для набора определенных Hibernate-сущностей из таблиц существующей БД.
Сразу оговорюсь, что статья не углубляется в детали рассматриваемых технологий и, по сути, представляет собой рецепт для решения конкретной задачи.
Для демонстрации гибкости конфигурации мы изменим стандартную стратегию наименования Hibernate-классов из названий таблиц БД на свою. Причина отказа от стандартной стратегии реверса заключается в том, что часто названия таблиц в БД представляют в виде слов множественного числа для имен сущностей, реализуемых таблицами. При использовании в таком случае стандартной стратегии наименования, классы будут иметь малоинформативные имена.
Примеры:
Результатом реверса со стратегией именования по умолчанию для такой схемы будут следующие классы:
В итоге понимать операции с объектами данных сущностей в Java-коде будет не просто — согласитесь, сложно догадаться, что возвращает метод класса Customers
Да и вообще оперировать с единичными объектами классов с именами во множественном числе не очень удобно.
Для решения такой проблемы можно использовать свои стратегии именования, создавая новые классы и переопределяя методы уже существующих стратегий.
Рассмотрим исходник:
Здесь мы переопределяем метод tableToClassName(), в теле которого, сначала получаем стандартное имя класса для данной таблица, после чего отрезаем суффикс множественного числа. После применения этой стратегии в процессе реверса, имена классов и методов в Hibernate-сущностях будут более четко отражать смысл сущностей схемы.
Переходим к заключительной части генерации файлов Hibernate-сущностей.
Выполняем следующую последовательность действий:
1. Скомпилируем вышеописанный класс как java-библиотеку.
2. Опишем файл reveng.xml в котором укажем выбранные для реверс-инжениринга сущности:
3. Затем создадим build.xml — Ant-скрипт для генерации файлов на основе следующего шаблона:
В тэге path здесь определяются пути к используемым при генерации классам (Hibernate, Hibernate Tools, наша MyNamingStrategy). Тэги hbm2hbmxml и hbm2java указывают инструментам о создании XML-маппингов и POJO-классов соответсвенно. Пути для генерируемых файлов можно контролировать с помощью аргументов destdir соответсвующих тэгов.
У тэга hbm2java есть два важных, но необязательных аттрибута:
В результате в указанных директориях мы получим набор сгенерированых POJO-классов и XML-маппингов с «правильными» именами.
Несомненно, наилучшим способом решения проблемы, как в плане понимания структуры базы, так и в плане чистоты кода, будет описание классов и маппингов вручную.
Но когда схема базы приличного масштаба, то очень хочется этот процесс автоматизировать… Или хотя бы создать скелеты POJO-классов и XML-файлов, которые можно будет вручную скорректировать позже.
Для автоматизации процесса (и не только) существует пакет Hibernate Tools, позволяющий описать задачи для реверса схемы существующей БД в файлы сущностей Hibernate, используя возможности инструмента сборки Java приложений Ant.
В популярной среде разработки Eclipse и NetBeans существуют визарды, позволяющие упростить процесс конфигурирования Hibernate Tools, но мы их использовать не будем(я использую NetBeans, но встроенный Hibernate-визард разочаровал меня отсутствием гибкой конфигурации реверса, возможности визардов Eclipse я не исследовал, но предполагаю, что они не сильно отличаются от NetBeans'овых...). Итак, мы выбираем хардкорный путь генерации через Ant-скрипты.
Перед нами стоит задача сгенерировать скелеты POJO-классов и XML-маппинги для набора определенных Hibernate-сущностей из таблиц существующей БД.
Сразу оговорюсь, что статья не углубляется в детали рассматриваемых технологий и, по сути, представляет собой рецепт для решения конкретной задачи.
Для демонстрации гибкости конфигурации мы изменим стандартную стратегию наименования Hibernate-классов из названий таблиц БД на свою. Причина отказа от стандартной стратегии реверса заключается в том, что часто названия таблиц в БД представляют в виде слов множественного числа для имен сущностей, реализуемых таблицами. При использовании в таком случае стандартной стратегии наименования, классы будут иметь малоинформативные имена.
Примеры:
таблица отражающая сущность клиентов именуется не CUSTOMER, а CUSTOMERS;
таблица учетных записей - не ACCOUNT, а ACCOUNTS;
таблица типов пользователей - не USER_TYPE, а USER_TYPES...
Результатом реверса со стратегией именования по умолчанию для такой схемы будут следующие классы:
CUSTOMERS -> class Customers;
ACCOUNTS -> class Accounts;
USER_TYPES -> class UserTypes...
В итоге понимать операции с объектами данных сущностей в Java-коде будет не просто — согласитесь, сложно догадаться, что возвращает метод класса Customers
Set getAccountses();
Да и вообще оперировать с единичными объектами классов с именами во множественном числе не очень удобно.
Для решения такой проблемы можно использовать свои стратегии именования, создавая новые классы и переопределяя методы уже существующих стратегий.
Рассмотрим исходник:
import org.hibernate.cfg.reveng.DelegatingReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.ReverseEngineeringStrategy;
import org.hibernate.cfg.reveng.TableIdentifier;
public class MyNamingStrategy extends DelegatingReverseEngineeringStrategy {
/*
* @param delegate {@link org.hibernate.cfg.reveng.ReverseEngineeringStrategy}
*/
public MyNamingStrategy(ReverseEngineeringStrategy delegate) {
super(delegate);
}
@Override
public String tableToClassName(TableIdentifier tableIdentifier) {
String tableName = super.tableToClassName(tableIdentifier);
if (tableName.endsWith("ses")) {
tableName = tableName.substring(0, tableName.length() - 2);
} else if (tableName.endsWith("s")) {
tableName = tableName.substring(0, tableName.length() - 1);
}
return tableName;
}
}
Здесь мы переопределяем метод tableToClassName(), в теле которого, сначала получаем стандартное имя класса для данной таблица, после чего отрезаем суффикс множественного числа. После применения этой стратегии в процессе реверса, имена классов и методов в Hibernate-сущностях будут более четко отражать смысл сущностей схемы.
Переходим к заключительной части генерации файлов Hibernate-сущностей.
Выполняем следующую последовательность действий:
1. Скомпилируем вышеописанный класс как java-библиотеку.
2. Опишем файл reveng.xml в котором укажем выбранные для реверс-инжениринга сущности:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-reverse-engineering PUBLIC "-//Hibernate/Hibernate Reverse Engineering DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-reverse-engineering-3.0.dtd">
<hibernate-reverse-engineering>
<schema-selection match-schema="DBSCHEMA"/>
<table-filter match-name="CUSTOMERS"/>
<table-filter match-name="USERS"/>
<table-filter match-name="USER_TYPES"/>
<table-filter match-name="ACCOUNTS"/>
</hibernate-reverse-engineering>
3. Затем создадим build.xml — Ant-скрипт для генерации файлов на основе следующего шаблона:
<?xml version="1.0" encoding="UTF-8"?>
<project name="reverse" default="all" basedir=".">
<path id="project.classpath">
<!-- Путь к библиотекам Hibernate и Hibernate Tools -->
<fileset dir="../lib">
<include name="**/*.jar"/>
</fileset>
<!-- Путь к библиотеке с нашей страегией именования -->
<fileset dir="../dist">
<include name="**/*.jar"/>
</fileset>
</path>
<taskdef name="hibernatetool"
classname="org.hibernate.tool.ant.HibernateToolTask"
classpathref="project.classpath"/>
<target name="all">
<hibernatetool>
<jdbcconfiguration
configurationfile="hibernate.cfg.xml"
packagename="hibernate.entities"
revengfile="reveng.xml"
reversestrategy="MyNamingStrategy" />
<hbm2hbmxml destdir="." />
<hbm2java destdir="." />
</hibernatetool>
</target>
</project>
В тэге path здесь определяются пути к используемым при генерации классам (Hibernate, Hibernate Tools, наша MyNamingStrategy). Тэги hbm2hbmxml и hbm2java указывают инструментам о создании XML-маппингов и POJO-классов соответсвенно. Пути для генерируемых файлов можно контролировать с помощью аргументов destdir соответсвующих тэгов.
У тэга hbm2java есть два важных, но необязательных аттрибута:
- jdk5=«true|false» — генерация кода классов с фичами JDK5
- ejb3=«true|false» — генерация EJB3-аннотаций в коде классов
- configurationfile — файл конфигурации hibernate.cfg.xml
- packagename — имя пакета для будущих POJO-классов
- revengfile — файл revenge.xml из прошлого пункта
- reversestrategy — имя класса с нашей стратегией именования (не забываем добавить путь к классу в тэге path)
...>ant
Buildfile: build.xml
all:
[hibernatetool] Executing Hibernate Tool with a JDBC Configuration (for reverse engineering)
[hibernatetool] 1. task: hbm2hbmxml (Generates a set of hbm.xml files)
[hibernatetool] 2. task: hbm2java (Generates a set of .java files)
BUILD SUCCESSFUL
Total time: 9 seconds
В результате в указанных директориях мы получим набор сгенерированых POJO-классов и XML-маппингов с «правильными» именами.