Using Hibernate Annotations and Maven

Hibernate annotations can sometimes be fun, and sometimes be a real pain. Regardless, for those of us who have chosen to use annotations, there are some slick ways to use Maven to generate a DDL as well as run the DDL against a database.

Using maven-antrun-plugin and HibernateTool

To start off, we need to have a hibernate.cfg.xml:

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <property name="hibernate.show_sql">false</property>
        <property name="hibernate.format_sql">true</property>
        <property name="use_sql_comments">true</property>

        <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>
        <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
        <property name="hibernate.connection.url">jdbc:hsqldb:mem:someDb</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>

        <!-- add classes to map from here -->
        <mapping class="ca.intelliware.someProject.SomeClass" />
        ....
    </session-factory>
</hibernate-configuration>

We can then add the maven-antrun-plugin to our pom.xml. The following will look for a task called generateDDLin the build.xml file:

<project>
    <build>
        <plugins>
            ....
            <plugin>
                <artifactId>maven-antrun-plugin</artifactId>
                <executions>
                    <execution>
                        <id>generate-ddl</id>
                        <phase>process-classes</phase>
                        <goals>
                            <goal>run</goal>
                        </goals>
                        <configuration>
                            <tasks>
                                <ant antfile="${basedir}/build.xml" inheritRefs="true">
                                    <target name="generateDDL" />
                                </ant>
                            </tasks>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>hsqldb</groupId>
                        <artifactId>hsqldb</artifactId>
                        <version>1.8.0.7</version>
                    </dependency>
                    <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-annotations</artifactId>
                        <version>3.2.1.ga</version>
                    </dependency>
                    <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-tools</artifactId>
                        <version>3.2.0.beta9a</version>
                    </dependency>
                    <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-entitymanager</artifactId>
                         <version>3.2.1.ga</version>
                    </dependency>
                    <dependency>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                        <version>1.2.14</version>
                    </dependency>
                </dependencies>
            </plugin>
            ....
        </plugins>
    </build>
    ....
</project>

You will likely need to add the dependencies listed above to the <dependencies> tag at the highest level of the pom.xml as well.

Lastly, we need the contents of the build.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<project name="someProject" default="generateDDL">
    <description>DDL generation</description>
    <target name="generateDDL">
        <mkdir dir="${basedir}/target/generated-sources/schema" />
        <taskdef name="hibernatetool" classname="org.hibernate.tool.ant.HibernateToolTask" />
        <hibernatetool destdir="${basedir}/target/generated-sources">
            <classpath refid="maven.compile.classpath" />
            <annotationconfiguration configurationfile="${basedir}/src/main/resources/hibernate.cfg.xml"/>
            <hbm2ddl drop="true" create="true" export="${export}"
                    outputfilename="schema.ddl" delimiter=";" format="true" />
        </hibernatetool>
    </target>
</project>

The schema can then be generated by running:

mvn process-classes

This will provide output similar to:

[INFO] [compiler:compile]
[INFO] Nothing to compile - all classes are up to date
[INFO] [antrun:run {execution: generate-ddl}]
[INFO] Executing tasks

generateDDL:
[hibernatetool] Executing Hibernate Tool with a Hibernate Annotation/EJB3 Configuration
[hibernatetool] 1. task: hbm2ddl (Generates database schema)
Jul 5, 2007 11:03:58 AM org.hibernate.cfg.annotations.Version <clinit>
INFO: Hibernate Annotations 3.2.1.GA
Jul 5, 2007 11:03:58 AM org.hibernate.cfg.Environment <clinit>
INFO: Hibernate 3.2.1
Jul 5, 2007 11:03:58 AM org.hibernate.cfg.Environment <clinit>
INFO: hibernate.properties not found
Jul 5, 2007 11:03:58 AM org.hibernate.cfg.Environment buildBytecodeProvider
INFO: Bytecode provider name : cglib
Jul 5, 2007 11:03:58 AM org.hibernate.cfg.Environment <clinit>
INFO: using JDK 1.4 java.sql.Timestamp handling
Jul 5, 2007 11:03:58 AM org.hibernate.cfg.Configuration configure
INFO: configuring from file: hibernate.cfg.xml
...
INFO: Using dialect: org.hibernate.dialect.HSQLDialect
Jul 5, 2007 11:03:58 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: Running hbm2ddl schema export
Jul 5, 2007 11:03:58 AM org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: writing generated schema to file: C:\eclipse\workspace\someProject\target\generated-sources\schema\schema.ddl
....
<schema info here>
...
INFO: schema export complete
[INFO] Executed tasks
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4 seconds
[INFO] Finished at: Thu Jul 05 11:03:59 EDT 2007
[INFO] Final Memory: 6M/12M
[INFO] ------------------------------------------------------------------------

and you can find the schema in /target/generated-sources/schema/schema.ddl

NOTE: The first time you run the schema generation, you will probably want to change the drop=”true” to drop=”false”, as you probably don’t have a database yet. When drop=”true” is set, it will add the necessary alter table statements to drop foreign key constraints so that it can then drop tables. If you don’t have any tables, this will fail.

Using sql-maven-plugin

Add the following to your pom.xml:

<project>
    ...
    <build>
        ...
        <plugins>
            ...
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>sql-maven-plugin</artifactId>
                <version>1.0</version>
                <executions>
                    <execution>
                        <id>create-schema</id>
                        <phase>process-test-resources</phase>
                        <goals>
                            <goal>execute</goal>
                        </goals>
                        <configuration>
                            <autocommit>true</autocommit>
                            <srcFiles>
                                <srcFile>target/generated-sources/schema/ontrace.ddl</srcFile>
                            </srcFiles>
                        </configuration>
                    </execution>
                </executions>
                <dependencies>
                    <dependency>
                        <groupId>hsqldb</groupId>
                        <artifactId>hsqldb</artifactId>
                        <version>1.8.0.7</version>
                    </dependency>
                </dependencies>
                <configuration>
                    <driver>org.hsqldb.jdbcDriver</driver>
                    <username>sa</username>
                    <password></password>
                    <url>jdbc:hsqldb:mem:someDb</url>
                    <autocommit>true</autocommit>
                    <skip>${maven.test.skip}</skip>
                </configuration>
            </plugin>
            ...
        </plugins>
        ...
    </build>
    ...
<project>

The schema can be pushed to the database using:

mvn process-test-resources

which will create the schema as part of the process-classes phase, and produce output of interest (in addition to the output from the process-classesphase) similar to:

...
INFO: schema export complete
[INFO] Executed tasks
[INFO] [resources:testResources]
[INFO] Using default encoding to copy filtered resources.
[INFO] [sql:execute {execution: create-schema}]
[INFO] Executing file: c:\eclipse\workspace\someProject\target\generated-sources\schema\schema.ddl
[INFO] 6 of 6 SQL statements executed successfully
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESSFUL
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4 seconds
[INFO] Finished at: Thu Jul 05 11:18:27 EDT 2007
[INFO] Final Memory: 6M/12M
[INFO] ------------------------------------------------------------------------

NOTE: These goals get run as part of a normal build. So the schema will get generated each time the build hits the process-classes phase (ie. once the classes have compiled), and the schema will get pushed to the database as part of process-test-resources (ie. just prior to the unit tests being run).

It's only fair to share...
Share on FacebookGoogle+Tweet about this on TwitterShare on LinkedIn

Leave a Reply