1

Is there a gradle plugin or any other means of calling the hibernate-tools hbm2ddl task to generate a database schema from annotated classes, without having to list all the entities (@Entity) in some configuration file but having them discovered in the classpath?

Preferably for Hibernate 5 but Hibernate 4 will also do.

xtian
  • 2,908
  • 2
  • 30
  • 43

1 Answers1

0

I finally made it happen by moving the persistence.xml file around.

In my scenario I have some library entities and some application entities for which I want to generate a schema. Apparently I need to list the library entities in persistence.xml, which is fine as they don't change often, but in order to have the application entities be picked up from the classpath without listing them in the persistence file I had to ensure that both the classes and the persistence.xml file were loaded by the same classloader (I guess).

This is what works.

Library entities: MyCustomer, MyInvoice

Application entities: MyBook, MyBooking

/src/main/resources/META-INF/persistence.xml

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
             version="2.0">

   <persistence-unit name="defaultPersistenceUnit">
        <!-- List the library classes only -->
        <class>net.mylibrary.entity.MyCustomer</class>
        <class>net.mylibrary.entity.MyInvoice</class>

      <properties>
            <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
            <property name="hibernate.connection.username" value="myusr"/>
            <property name="hibernate.connection.password" value="mypwd"/>
            <property name="hibernate.connection.url" value="jdbc:mysql://localhost/mydb"/>
            <property name="hibernate.dialect" value="org.hibernate.dialect.MySQL5Dialect"/>
      </properties>
   </persistence-unit>
</persistence>

build.gradle:

apply plugin: 'war'
apply plugin: 'eclipse-wtp'

repositories {
    jcenter()
    mavenLocal()
}

dependencies {
    compile ... my project dependencies ...
}

configurations {
    hibtools
}

dependencies {
    hibtools 'net.mylibrary:MyEntities:1.0' // Library for MyCustomer and MyInvoice
    hibtools 'org.hibernate:hibernate-tools:4.+',
        'mysql:mysql-connector-java:5.+'
    hibtools files("$buildDir/classes/main") // MyBook and MyBooking
}

task createSchema(dependsOn: ['build', 'copyPersistenceUnit']) << {     
    ant.taskdef(name: 'hibernatetool',
            classname: 'org.hibernate.tool.ant.HibernateToolTask',
            classpath: configurations.hibtools.asPath)
    ant.hibernatetool(destdir: 'schema') {
        ant.jpaconfiguration(persistenceunit: 'defaultPersistenceUnit')
        ant.hbm2ddl(drop: 'false', export: 'false', outputfilename: 'mydb.sql')
    }
}

task copyPersistenceUnit(type: Copy) {
    from "$buildDir/resources/main/META-INF/persistence.xml"
    into "$buildDir/classes/main/META-INF/"
}

The result is a ddl with tables for MyCustomer, MyInvoice, MyBook, MyBooking, even if MyBook and MyBooking aren't listed anywhere and could be added or deleted without touching the configuration.

The trick here is to copy the persistence.xml file from the resources folder to the classes folder. If you don't do this, in order to have it found you need to add the resources path to the hibtools configuration with something like:

hibtools files(["$buildDir/resources/main", "$buildDir/classes/main"])

but doing this will prevent your application entities from being discovered.

This works with Hibernate 4. Using the current Hibernate 5 alpha tool gives an empty ddl file.

xtian
  • 2,908
  • 2
  • 30
  • 43