5

A followup question to my previous question: Generate an SQL DB creation script with Hibernate 4

The goal is to have a command line tool able to generate a file with the SQL schema of a given persistence unit (similarly to the hibernatetool-hbm2ddl Ant task present in the Hibernate Tools).

This, as per the answer to my previous question, can be achieved with org.hibernate.tool.hbm2ddl.SchemaExport.

Instead of adding all the entities to the Configuration (as suggested in the previous answer) I would like to specify a PersistenceUnit.

Is it possible to add a persistence unit to an Hibernate Configuration?

Something like

Properties properties = new Properties();
properties.put( "hibernate.dialect", "org.hibernate.dialect.PostgreSQLDialect" );
...
EntityManagerFactory entityManagerFactory =
    Persistence.createEntityManagerFactory( "persistentUnitName", properties );
Configuration configuration = new Configuration();

... missing part ...

SchemaExport schemaExport = new SchemaExport( configuration );
schemaExport.setOutputFile( "schema.sql" );
...

Edit as requested in the comments a sample persistence.xml. Each class is annotated with @Entity

<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_1_0.xsd"
    version="1.0"
>

    <persistence-unit
        name="doiPersistenceUnit"
        transaction-type="JTA"
    >

        <provider>org.hibernate.ejb.HibernatePersistence</provider>
        <jta-data-source>jdbc/doi</jta-data-source>


        <class>ch.ethz.id.wai.doi.bo.Doi</class>
        [...]
        <class>ch.ethz.id.wai.doi.bo.DoiPool</class>

        <exclude-unlisted-classes>true</exclude-unlisted-classes>

        <properties>
            <property name="hibernate.show_sql"                     value="false" />
            <property name="hibernate.format_sql"                   value="false" />
            <property name="hibernate.connection.characterEncoding" value="utf8" />
            <property name="hibernate.connection.charSet"           value="utf8" />
        </properties>

    </persistence-unit>

</persistence>
Community
  • 1
  • 1
Matteo
  • 14,696
  • 9
  • 68
  • 106
  • so you want to save the `config.addAnnotatedClass(MyMappedPojo1.class);` lines? – yair Jan 07 '13 at 07:01
  • @yair yes I would like to avoid to specify all the classes manually (and avoid to hard-code them). I know I could parse the persistence.xml file but I suspect there is an easier way. – Matteo Jan 07 '13 at 07:21
  • I think you're missing also passing dialect into configuration - it will fail when SchemaExport is created. – kboom Aug 07 '14 at 09:22

1 Answers1

6

Well, if your classes are mapped via xml mappings (hbms) - you can add the documnets or jar files that include the xmls straight to the Configuration instance using config.addJar(myJarFile) and config.add(myXmlFile).

However, if you want your annotated classes to be scanned - I know of no such straightforward option through Hibernate (addPackage adds metadata and not classes).

You may implement your own scan logic and add all annotated classes with config.addAnnotatedClass(myAnnotatedClass) (or perhaps do it per specific packages you know for containing you ORM classes and thus maybe save some time).

UPDATE 2

Oh, even better, you can just iterate the persistence unit's ManagedTypes via getManagedTypes():

EntityManagerFactory entityManagerFactory =
    Persistence.createEntityManagerFactory( unitName, config.getProperties() );
final Set<ManagedType<?>> managedTypes =
    entityManagerFactory.getMetamodel().getManagedTypes();
    for ( ManagedType<?> managedType : managedTypes ) {
    final Class<?> javaType = managedType.getJavaType();
    config.addAnnotatedClass( javaType );
}

UPDATE

You can determine the PersistenceUnit of each Entity - without parsing the xml - by checking against the relevant EntityManagerFactory:

Class aClass = ... // get the class from your scanning
EntityManagerFactory entityManagerFactory =
    Persistence.createEntityManagerFactory( unitName, config.getProperties() );
ManagedType<?> managedType = null;
try {
    managedType = entityManagerFactory.getMetamodel().managedType( aClass );
} catch ( IllegalArgumentException e ) {
    // happens when aClass isn't a type managed by the persistence unit
}
if ( managedType != null ) {
    config.addAnnotatedClass( aClass );
}

Make sure to use different Configuration instances for each persistence unit. Otherwise, annotated classes would just accumulate and so also the DDL.

I tried it and it worked great - printed two distinct DDLs for two different persistence units.

yair
  • 8,945
  • 4
  • 31
  • 50
  • the classes are annotated. Scanning the jar files for annotations could be an option but I would still have to parse the parse the persistence.xml files to know to which persistence unit a given \@Entity belongs – Matteo Jan 07 '13 at 09:21
  • @Matteo could you please post your `persistence.xml`? – yair Jan 07 '13 at 11:02
  • there is no single persistence.xml but many of them (hence the need for my tool) I will add one example. – Matteo Jan 07 '13 at 12:09
  • Ok but to get the classes I have to list all the classes present in the classpath or did I get it wrong? I was hoping for a way to simply list the classes managed by a given persistence unit but your solution will do :-) – Matteo Jan 08 '13 at 06:18
  • @Matteo seems you're right, there _is_ a better solution. See again **UPDATE 2**. – yair Jan 08 '13 at 08:25