Revert deferred DDL changes and re-oreder database migrations

Schema initialization now happens in @PostConstruct (effectively)
whether it is via the Hibernate EntityManagerFactory or the
Boot DataSourceInitialization (in addition or instead). The data.sql
script if it exists is still executed on an event fired from the
other places, so those tests are passing.

Flyway and liquibase have bean factory post processors (like
the one they use to order the audit aspect in Spring Data) that
enforce a dependency on those components from the EntityManagerFactory.
So Hibernate validation is still happy (and there are 2 tests to
prove it now as well).

Fixes gh-1022
This commit is contained in:
Dave Syer 2014-06-04 09:44:02 +01:00
parent f7d1aab9f3
commit 74166e770a
12 changed files with 329 additions and 137 deletions

View File

@ -16,11 +16,21 @@
package org.springframework.boot.autoconfigure.flyway;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.flywaydb.core.Flyway;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@ -32,10 +42,18 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import static java.util.Arrays.asList;
import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors;
import static org.springframework.beans.factory.BeanFactoryUtils.transformedBeanName;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Flyway database migrations.
@ -53,6 +71,7 @@ public class FlywayAutoConfiguration {
@Configuration
@ConditionalOnMissingBean(Flyway.class)
@EnableConfigurationProperties(FlywayProperties.class)
@Import(FlywayJpaDependencyConfiguration.class)
public static class FlywayConfiguration {
@Autowired
@ -105,4 +124,57 @@ public class FlywayAutoConfiguration {
}
@Configuration
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
protected static class FlywayJpaDependencyConfiguration implements
BeanFactoryPostProcessor {
public static final String FLYWAY_JPA_BEAN_NAME = "flyway";
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
for (String beanName : getEntityManagerFactoryBeanNames(beanFactory)) {
BeanDefinition definition = getBeanDefinition(beanName, beanFactory);
definition.setDependsOn(StringUtils.addStringToArray(
definition.getDependsOn(), FLYWAY_JPA_BEAN_NAME));
}
}
private static BeanDefinition getBeanDefinition(String beanName,
ConfigurableListableBeanFactory beanFactory) {
try {
return beanFactory.getBeanDefinition(beanName);
}
catch (NoSuchBeanDefinitionException e) {
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
return getBeanDefinition(beanName,
(ConfigurableListableBeanFactory) parentBeanFactory);
}
throw e;
}
}
private static Iterable<String> getEntityManagerFactoryBeanNames(
ListableBeanFactory beanFactory) {
Set<String> names = new HashSet<String>();
names.addAll(asList(beanNamesForTypeIncludingAncestors(beanFactory,
EntityManagerFactory.class, true, false)));
for (String factoryBeanName : beanNamesForTypeIncludingAncestors(beanFactory,
AbstractEntityManagerFactoryBean.class, true, false)) {
names.add(transformedBeanName(factoryBeanName));
}
return names;
}
}
}

View File

@ -33,7 +33,6 @@ import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
@ -44,12 +43,11 @@ import org.springframework.util.StringUtils;
*/
@Configuration
@EnableConfigurationProperties(DataSourceProperties.class)
public class DataSourceInitialization implements
ApplicationListener<ContextRefreshedEvent> {
public class DataSourceInitialization {
private static Log logger = LogFactory.getLog(DataSourceAutoConfiguration.class);
@Autowired(required = false)
@Autowired
private DataSource dataSource;
@Autowired
@ -61,34 +59,11 @@ public class DataSourceInitialization implements
private boolean initialized = false;
@Bean
public ApplicationListener<DataSourceInitializedEvent> dataSourceInitializedListener() {
public ApplicationListener<DataSourceInitializedEvent> dataSourceInitializedListener(
DataSource dataSource) {
return new DataSourceInitializedListener();
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
if (this.properties.isDeferDdl()) {
boolean initialize = this.properties.isInitialize();
if (!initialize) {
logger.debug("Initialization disabled (not running DDL scripts)");
return;
}
runSchemaScripts();
}
}
@PostConstruct
protected void initialize() {
if (!this.properties.isDeferDdl()) {
boolean initialize = this.properties.isInitialize();
if (!initialize) {
logger.debug("Initialization disabled (not running DDL scripts)");
return;
}
runSchemaScripts();
}
}
private void runSchemaScripts() {
String schema = this.properties.getSchema();
if (schema == null) {
@ -172,6 +147,18 @@ public class DataSourceInitialization implements
private class DataSourceInitializedListener implements
ApplicationListener<DataSourceInitializedEvent> {
// Keep this in the nested class so that it doesn't have to be called before the
// listener is instantiated (ordering problems otherwise)
@PostConstruct
protected void initialize() {
boolean initialize = DataSourceInitialization.this.properties.isInitialize();
if (!initialize) {
logger.debug("Initialization disabled (not running DDL scripts)");
return;
}
runSchemaScripts();
}
@Override
public void onApplicationEvent(DataSourceInitializedEvent event) {
runDataScripts();

View File

@ -46,8 +46,6 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
private boolean initialize = true;
private boolean deferDdl = false;
private String platform = "all";
private String schema;
@ -158,14 +156,6 @@ public class DataSourceProperties implements BeanClassLoaderAware, InitializingB
this.initialize = initialize;
}
public void setDeferDdl(boolean deferDdl) {
this.deferDdl = deferDdl;
}
public boolean isDeferDdl() {
return this.deferDdl;
}
public String getPlatform() {
return this.platform;
}

View File

@ -16,12 +16,22 @@
package org.springframework.boot.autoconfigure.liquibase;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import liquibase.integration.spring.SpringLiquibase;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
@ -32,15 +42,24 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.orm.jpa.AbstractEntityManagerFactoryBean;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import static java.util.Arrays.asList;
import static org.springframework.beans.factory.BeanFactoryUtils.beanNamesForTypeIncludingAncestors;
import static org.springframework.beans.factory.BeanFactoryUtils.transformedBeanName;
/**
* {@link EnableAutoConfiguration Auto-configuration} for Liquibase.
*
* @author Marcel Overdijk
* @author Dave Syer
* @since 1.1.0
*/
@Configuration
@ -53,6 +72,7 @@ public class LiquibaseAutoConfiguration {
@Configuration
@ConditionalOnMissingBean(SpringLiquibase.class)
@EnableConfigurationProperties(LiquibaseProperties.class)
@Import(LiquibaseJpaDependencyConfiguration.class)
public static class LiquibaseConfiguration {
@Autowired
@ -87,4 +107,58 @@ public class LiquibaseAutoConfiguration {
return liquibase;
}
}
@Configuration
@ConditionalOnClass(LocalContainerEntityManagerFactoryBean.class)
@ConditionalOnBean(AbstractEntityManagerFactoryBean.class)
protected static class LiquibaseJpaDependencyConfiguration implements
BeanFactoryPostProcessor {
public static final String LIQUIBASE_JPA_BEAN_NAME = "liquibase";
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
for (String beanName : getEntityManagerFactoryBeanNames(beanFactory)) {
BeanDefinition definition = getBeanDefinition(beanName, beanFactory);
definition.setDependsOn(StringUtils.addStringToArray(
definition.getDependsOn(), LIQUIBASE_JPA_BEAN_NAME));
}
}
private static BeanDefinition getBeanDefinition(String beanName,
ConfigurableListableBeanFactory beanFactory) {
try {
return beanFactory.getBeanDefinition(beanName);
}
catch (NoSuchBeanDefinitionException e) {
BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
if (parentBeanFactory instanceof ConfigurableListableBeanFactory) {
return getBeanDefinition(beanName,
(ConfigurableListableBeanFactory) parentBeanFactory);
}
throw e;
}
}
private static Iterable<String> getEntityManagerFactoryBeanNames(
ListableBeanFactory beanFactory) {
Set<String> names = new HashSet<String>();
names.addAll(asList(beanNamesForTypeIncludingAncestors(beanFactory,
EntityManagerFactory.class, true, false)));
for (String factoryBeanName : beanNamesForTypeIncludingAncestors(beanFactory,
AbstractEntityManagerFactoryBean.class, true, false)) {
names.add(transformedBeanName(factoryBeanName));
}
return names;
}
}
}

View File

@ -0,0 +1,53 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.boot.autoconfigure.orm.jpa;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.boot.autoconfigure.jdbc.DataSourceInitialization.DataSourceInitializedEvent;
import org.springframework.context.ApplicationContext;
public class DataSourceInitializedPublisher implements BeanPostProcessor {
@Autowired
private ApplicationContext applicationContext;
private DataSource dataSource;
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean instanceof DataSource) {
// Normally this will be the right DataSource
this.dataSource = (DataSource) bean;
}
if (bean instanceof EntityManagerFactory && this.dataSource != null) {
this.applicationContext.publishEvent(new DataSourceInitializedEvent(
this.dataSource));
}
return bean;
}
}

View File

@ -21,7 +21,6 @@ import java.util.Map;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import org.hibernate.jpa.boot.spi.Bootstrap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
@ -29,15 +28,11 @@ import org.springframework.boot.autoconfigure.condition.ConditionOutcome;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.SpringBootCondition;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.autoconfigure.jdbc.DataSourceInitialization.DataSourceInitializedEvent;
import org.springframework.boot.autoconfigure.orm.jpa.EntityManagerFactoryBuilder.EntityManagerFactoryBeanCallback;
import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration.HibernateEntityManagerCondition;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.type.AnnotatedTypeMetadata;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.AbstractJpaVendorAdapter;
@ -73,48 +68,7 @@ public class HibernateJpaAutoConfiguration extends JpaBaseConfiguration {
@Override
protected Map<String, String> getVendorProperties() {
return this.properties.getInitialHibernateProperties(this.dataSource);
}
@Override
protected EntityManagerFactoryBeanCallback getVendorCallback() {
final Map<String, String> map = this.properties
.getHibernateProperties(this.dataSource);
return new EntityManagerFactoryBeanCallback() {
@Override
public void execute(
LocalContainerEntityManagerFactoryBean entityManagerFactoryBean) {
HibernateJpaAutoConfiguration.this.applicationContext
.addApplicationListener(new DeferredSchemaAction(
entityManagerFactoryBean, map));
}
};
}
private class DeferredSchemaAction implements
ApplicationListener<ContextRefreshedEvent> {
private Map<String, String> map;
private LocalContainerEntityManagerFactoryBean factory;
public DeferredSchemaAction(LocalContainerEntityManagerFactoryBean factory,
Map<String, String> map) {
this.factory = factory;
this.map = map;
}
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
String ddlAuto = this.map.get("hibernate.hbm2ddl.auto");
if (ddlAuto == null || "none".equals(ddlAuto) || "".equals(ddlAuto)) {
return;
}
Bootstrap.getEntityManagerFactoryBuilder(
this.factory.getPersistenceUnitInfo(), this.map).generateSchema();
HibernateJpaAutoConfiguration.this.applicationContext
.publishEvent(new DataSourceInitializedEvent(
HibernateJpaAutoConfiguration.this.dataSource));
}
return this.properties.getHibernateProperties(this.dataSource);
}
static class HibernateEntityManagerCondition extends SpringBootCondition {

View File

@ -25,16 +25,23 @@ import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.boot.autoconfigure.AutoConfigurationPackages;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration.DataSourceInitializedRegistrar;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Primary;
import org.springframework.core.type.AnnotationMetadata;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@ -54,6 +61,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter
* @author Oliver Gierke
*/
@EnableConfigurationProperties(JpaProperties.class)
@Import(DataSourceInitializedRegistrar.class)
public abstract class JpaBaseConfiguration implements BeanFactoryAware {
private ConfigurableListableBeanFactory beanFactory;
@ -107,7 +115,9 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
protected abstract Map<String, String> getVendorProperties();
protected abstract EntityManagerFactoryBuilder.EntityManagerFactoryBeanCallback getVendorCallback();
protected EntityManagerFactoryBuilder.EntityManagerFactoryBeanCallback getVendorCallback() {
return null;
}
protected String[] getPackagesToScan() {
if (AutoConfigurationPackages.has(this.beanFactory)) {
@ -145,4 +155,24 @@ public abstract class JpaBaseConfiguration implements BeanFactoryAware {
}
protected static class DataSourceInitializedRegistrar implements
ImportBeanDefinitionRegistrar {
private static final String BEAN_NAME = "dataSourceInitializedPublisher";
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
if (!registry.containsBeanDefinition(BEAN_NAME)) {
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DataSourceInitializedPublisher.class);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
// We don't need this one to be post processed otherwise it can cause a
// cascade of bean instantiation that we would rather avoid.
beanDefinition.setSynthetic(true);
registry.registerBeanDefinition(BEAN_NAME, beanDefinition);
}
}
}
}

View File

@ -103,23 +103,13 @@ public class JpaProperties {
/**
* Get configuration properties for the initialization of the main Hibernate
* EntityManagerFactory. The result will always have ddl-auto=none, so that the schema
* generation or validation can be deferred to a later stage.
* @param dataSource the DataSource in case it is needed to determine the properties
* @return some Hibernate properties for configuration
*/
public Map<String, String> getInitialHibernateProperties(DataSource dataSource) {
return this.hibernate.getAdditionalProperties(this.properties);
}
/**
* Get the full configuration properties for the Hibernate EntityManagerFactory.
* EntityManagerFactory.
*
* @param dataSource the DataSource in case it is needed to determine the properties
* @return some Hibernate properties for configuration
*/
public Map<String, String> getHibernateProperties(DataSource dataSource) {
return this.hibernate
.getDeferredAdditionalProperties(this.properties, dataSource);
return this.hibernate.getAdditionalProperties(this.properties, dataSource);
}
public static class Hibernate {
@ -130,8 +120,6 @@ public class JpaProperties {
private String ddlAuto;
private boolean deferDdl = true;
public Class<?> getNamingStrategy() {
return this.namingStrategy;
}
@ -143,7 +131,7 @@ public class JpaProperties {
@Deprecated
public void setNamingstrategy(Class<?> namingStrategy) {
logger.warn("The property spring.jpa.namingstrategy has been renamed, "
+ "please update your configuration to use naming-strategy");
+ "please update your configuration to use namingStrategy or naming-strategy or naming_strategy");
this.setNamingStrategy(namingStrategy);
}
@ -151,19 +139,8 @@ public class JpaProperties {
return this.ddlAuto;
}
public void setDeferDdl(boolean deferDdl) {
this.deferDdl = deferDdl;
}
public boolean isDeferDdl() {
return this.deferDdl;
}
private String getDeferredDdlAuto(Map<String, String> existing,
private String getActualDdlAuto(Map<String, String> existing,
DataSource dataSource) {
if (!this.deferDdl) {
return "none";
}
String ddlAuto = this.ddlAuto != null ? this.ddlAuto
: getDefaultDdlAuto(dataSource);
if (!isAlreadyProvided(existing, "hbm2ddl.auto") && !"none".equals(ddlAuto)) {
@ -179,19 +156,8 @@ public class JpaProperties {
this.ddlAuto = ddlAuto;
}
private Map<String, String> getDeferredAdditionalProperties(
Map<String, String> properties, DataSource dataSource) {
Map<String, String> deferred = getAdditionalProperties(properties);
String ddlAuto = getDeferredDdlAuto(properties, dataSource);
if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) {
deferred.put("hibernate.hbm2ddl.auto", ddlAuto);
} else {
deferred.remove("hibernate.hbm2ddl.auto");
}
return deferred;
}
private Map<String, String> getAdditionalProperties(Map<String, String> existing) {
private Map<String, String> getAdditionalProperties(Map<String, String> existing,
DataSource dataSource) {
Map<String, String> result = new HashMap<String, String>();
if (!isAlreadyProvided(existing, "ejb.naming_strategy")
&& this.namingStrategy != null) {
@ -201,11 +167,12 @@ public class JpaProperties {
result.put("hibernate.ejb.naming_strategy",
DEFAULT_NAMING_STRATEGY.getName());
}
if (this.deferDdl) {
result.remove("hibernate.hbm2ddl.auto");
String ddlAuto = getActualDdlAuto(existing, dataSource);
if (StringUtils.hasText(ddlAuto) && !"none".equals(ddlAuto)) {
result.put("hibernate.hbm2ddl.auto", ddlAuto);
}
else {
result.put("hibernate.hbm2ddl.auto", this.ddlAuto);
result.remove("hibernate.hbm2ddl.auto");
}
return result;
}

View File

@ -19,6 +19,8 @@ package org.springframework.boot.autoconfigure.orm.jpa;
import javax.sql.DataSource;
import org.junit.Test;
import org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration;
import org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration;
import org.springframework.boot.test.EnvironmentTestUtils;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@ -43,9 +45,10 @@ public class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigura
}
@Test
public void testDataScriptWithDdlAuto() throws Exception {
public void testDataScriptWithMissingDdl() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.data:classpath:/city.sql",
// Missing:
"spring.datasource.schema:classpath:/ddl.sql");
setupTestConfiguration();
this.context.refresh();
@ -55,10 +58,9 @@ public class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigura
}
@Test
public void testDataScriptWithDeferredDdl() throws Exception {
public void testDataScript() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.data:classpath:/city.sql",
"spring.datasource.deferDdl:true");
"spring.datasource.data:classpath:/city.sql");
setupTestConfiguration();
this.context.refresh();
assertEquals(new Integer(1),
@ -111,4 +113,26 @@ public class HibernateJpaAutoConfigurationTests extends AbstractJpaAutoConfigura
assertThat(actual, not(equalTo("org.hibernate.cfg.EJB3NamingStrategy")));
}
@Test
public void testFlywayPlusValidation() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:false",
"flyway.locations:classpath:db/city",
"spring.jpa.hibernate.ddl-auto:validate");
setupTestConfiguration();
this.context.register(FlywayAutoConfiguration.class);
this.context.refresh();
}
@Test
public void testLiquibasePlusValidation() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:false",
"liquibase.changeLog:classpath:db/changelog/db.changelog-city.yaml",
"spring.jpa.hibernate.ddl-auto:validate");
setupTestConfiguration();
this.context.register(LiquibaseAutoConfiguration.class);
this.context.refresh();
}
}

View File

@ -0,0 +1,36 @@
databaseChangeLog:
- changeSet:
id: 1
author: dsyer
changes:
- createTable:
tableName: city
columns:
- column:
name: id
type: bigint
autoIncrement: true
constraints:
primaryKey: true
nullable: false
- column:
name: name
type: varchar(50)
constraints:
nullable: false
- column:
name: state
type: varchar(50)
constraints:
nullable: false
- column:
name: country
type: varchar(50)
constraints:
nullable: false
- column:
name: map
type: varchar(50)
constraints:
nullable: true

View File

@ -0,0 +1,7 @@
CREATE TABLE CITY (
id BIGINT GENERATED BY DEFAULT AS IDENTITY,
name VARCHAR(30),
state VARCHAR(30),
country VARCHAR(30),
map VARCHAR(30)
);

View File

@ -156,7 +156,6 @@ content into your application; rather pick only the properties that you need.
# DATASOURCE ({sc-spring-boot-autoconfigure}/jdbc/DataSourceAutoConfiguration.{sc-ext}[DataSourceAutoConfiguration] & {sc-spring-boot-autoconfigure}//jdbc/AbstractDataSourceConfiguration.{sc-ext}[AbstractDataSourceConfiguration])
spring.datasource.name= # name of the data source
spring.datasource.initialize=true # populate using data.sql
spring.datasource.deferDdl= # flag to indicate that schema scripts will run after the application starts (default false)
spring.datasource.schema= # a schema (DDL) script resource reference
spring.datasource.data= # a data (DML) script resource reference
spring.datasource.platform= # the platform to use in the schema resource (schema-${platform}.sql)
@ -191,7 +190,6 @@ content into your application; rather pick only the properties that you need.
spring.jpa.database=
spring.jpa.generate-ddl=false # ignored by Hibernate, might be useful for other vendors
spring.jpa.hibernate.naming-strategy= # naming classname
spring.jpa.hibernate.defer-ddl=true # defer processing of DDL until application is running
spring.jpa.hibernate.ddl-auto= # defaults to create-drop for embedded dbs
# SOLR ({sc-spring-boot-autoconfigure}/solr/SolrProperties.{sc-ext}[SolrProperties}])