2

I need on deployment schema generation for a webapp that uses JPA. The server is Wildfly 9 with Hibernate as JPA provider.

I can achieve this by adding

<property name="hibernate.hbm2ddl.auto" value="create" />

to persistence.xml.

Is there another way to set this property per webapp and on deployment in Wildfly 9? I also tried hibernate.properties, but this had no effect.

Tobias Liefke
  • 8,637
  • 2
  • 41
  • 58
Harald Albers
  • 1,913
  • 16
  • 20

3 Answers3

3

There is no webapp specific deployment property out of the box.

But you can set a webapp specific system property which you reference in your persistence.xml:

<persistence-unit >
  ...
  <properties>
    <property name="hibernate.hbm2ddl.auto" value="${mywebapp.hibernate.hbm2ddl.auto}" />
  </properties>
</persistence-unit>

A system property can be set in the standalone.conf(.bat) or in the standalone.xml:

<server xmlns="urn:jboss:domain:3.0"> 
  <extensions> ... </extensions>
  <system-properties>
    <property name="mywebapp.hibernate.hbm2ddl.auto" value="create"/>
    ...
  </system-properties>
  ...
</server>

Only drawback: you will have to set the system property in every environment - there is no default value.

Another option is to create an Integrator which sets the value in the settings. Unfortunately the config is read into the Settings object at the beginning and Settings.setAutoCreateSchema() and the other hibernate.hbm2ddl.auto specific properties are package protected, but you can set them with reflection:

public class AutoCreateSchemaIntegrator implements Integrator {

  @Override
  public void integrate(Configuration config, SessionFactoryImplementor factory, 
            SessionFactoryServiceRegistry registry) {
    Settings settings = factory.getSettings();

    try {
      Method setter = settings.getClass().getDeclaredMethod("setAutoCreateSchema", boolean.class);
      setter.setAccessible(true);
      setter.invoke(settings, myDeploymentSpecificProperty);
    } catch (ReflectiveOperationException | SecurityException e) {
      // handle exception
    }
  }
}

You need to write the full qualified class name of that integrator into META-INF/services/org.hibernate.integrator.spi.Integrator:

com.myproject.AutoCreateSchemaIntegrator

This is the best option if you want to determine the hbm2ddl setting dynamically.

Tobias Liefke
  • 8,637
  • 2
  • 41
  • 58
1

If you use Spring and JPA you can define all your persistence info in spring config xml. So you can include hibernate.hbm2ddl.auto to it. An example os Spring config file using org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean as EntityManagerFactory:

  <!-- DataSource reachable by jndi,  -->
  <jee:jndi-lookup id="myDataSource" jndi-name="jdbc/XADatasource" expected-type="javax.sql.DataSource" />

  <!-- jpa Properties used later in Hibernate configuration  -->
  <util:properties id="jpaHibernateProperties">
    <prop key="hibernate.transaction.jta.platform">
      org.hibernate.service.jta.platform.internal.JBossAppServerJtaPlatform
    </prop>
    <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
    <!-- validate | update | create | create-drop --> 
    <prop key="hibernate.hbm2ddl.auto">create</prop>
    <prop key="hibernate.show_sql">false</prop>
    <prop key="hibernate.format_sql">false</prop>
    <prop key="javax.persistence.transactionType">JTA</prop>
    <prop key="javax.persistence.validation.mode">AUTO</prop>
  </util:properties>

  <!-- Entity manager definition. No need of persistence.xml -->
  <bean id="myEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
    <property name="jpaVendorAdapter">
      <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
        <property name="databasePlatform" value="org.hibernate.dialect.Oracle10gDialect" />
      </bean>
    </property>
    <property name="packagesToScan">
      <list>
        <value>com.mycompany.myproject</value>
      </list>
    </property>
    <property name="persistenceUnitName" value="myPU" />
    <property name="jtaDataSource" ref="myDataSource" />
    <!-- Hibernate specific params defined previously -->
    <property name="jpaProperties" ref="jpaHibernateProperties" />
  </bean>
Ricardo Vila
  • 1,626
  • 1
  • 18
  • 34
  • Thanks for the answer. Unfortunately, I do not use Spring in my webapp, so I cannot test your solution. – Harald Albers Sep 25 '15 at 09:26
  • This solution is not deployment specific and makes no difference to the one with just a `persistence.xml`, as the given configuration file is usually shipped with the same artifact for all deployments. Although it is possible with Spring to use a second deployment specific configuration file, which would be a correct solution for the problem in a Spring application. – Tobias Liefke Sep 25 '15 at 12:25
  • Of course you can read Datasource or hibernate properties from a external properties file using a – Ricardo Vila Sep 25 '15 at 14:25
0

For wildfly you can use the ${env} expression with a default value:

<property name="mywebapp.hibernate.hbm2ddl.auto" value="${env.DB_AUTO:validate}"/>
Born78
  • 53
  • 6
  • This is an improvement to @Tobias Liefke's property-based solution, but it still has a drawback: It does not run out of the box. You still have to configure wildfly by setting a system property. The solution with the `Integrator` works better for me because I can have a persistence jar with an unmodified `peristence.xml`. I can then use this original persistence jar in an example webapp that adds the `Integrator`, and this webapp will autoconfigure the server without any previous tweaks. See the [example](https://github.com/albers/hibernate-integrator-spike). – Harald Albers Apr 05 '16 at 08:20
  • Also, this solution is not really **per webapp** because the same persistence jar can be used in multiple webapps. – Harald Albers Apr 05 '16 at 08:49
  • The Integrator solution has the drawback that you depend on a specific persistence provider (i.e. hibernate), so that your application is not portable in the sense of just depending on JPA. And of course that you have to write code using reflection .... – Born78 Apr 07 '16 at 18:45