Pull to refresh

Реверс-инжениринг схемы базы данных с использованием Ant и Hibernate Tools

Reading time7 min
Views2.4K
Часто у программистов Hibernate возникает задача по первоначальной конфигурации XML-маппингов и созданию POJO-классов на основе схемы из существующей базы данных.

Несомненно, наилучшим способом решения проблемы, как в плане понимания структуры базы, так и в плане чистоты кода, будет описание классов и маппингов вручную.
Но когда схема базы приличного масштаба, то очень хочется этот процесс автоматизировать… Или хотя бы создать скелеты 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-аннотаций в коде классов
Также стоит отметить аргументы тэга jdbcconfiguration:
  • configurationfile — файл конфигурации hibernate.cfg.xml
  • packagename — имя пакета для будущих POJO-классов
  • revengfile — файл revenge.xml из прошлого пункта
  • reversestrategy — имя класса с нашей стратегией именования (не забываем добавить путь к классу в тэге path)
4. Запускаем Ant в директории с build.xml и наслаждаемся процессом:
...>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-маппингов с «правильными» именами.
Tags:
Hubs:
+7
Comments2

Articles