Commit f4df9d97 authored by Phillip Webb's avatar Phillip Webb

Use lexical ordered DataSourceInitializer patterns

Align DataSourceInitializer to Spring Framework by lexically sorting
resolved resource patterns.

Fixes gh-6316
parent d6bf9775
......@@ -16,8 +16,8 @@
package org.springframework.boot.autoconfigure.jdbc;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import javax.annotation.PostConstruct;
......@@ -30,6 +30,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;
import org.springframework.jdbc.config.SortedResourcesFactoryBean;
import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils;
import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator;
import org.springframework.util.StringUtils;
......@@ -129,21 +130,27 @@ class DataSourceInitializer implements ApplicationListener<DataSourceInitialized
}
private List<Resource> getResources(String locations) {
List<Resource> resources = new ArrayList<Resource>();
for (String location : StringUtils.commaDelimitedListToStringArray(locations)) {
try {
for (Resource resource : this.applicationContext.getResources(location)) {
if (resource.exists()) {
resources.add(resource);
}
return getResources(
Arrays.asList(StringUtils.commaDelimitedListToStringArray(locations)));
}
private List<Resource> getResources(List<String> locations) {
SortedResourcesFactoryBean factory = new SortedResourcesFactoryBean(
this.applicationContext, locations);
try {
factory.afterPropertiesSet();
List<Resource> resources = new ArrayList<Resource>();
for (Resource resource : factory.getObject()) {
if (resource.exists()) {
resources.add(resource);
}
}
catch (IOException ex) {
throw new IllegalStateException(
"Unable to load resource from " + location, ex);
}
return resources;
}
catch (Exception ex) {
throw new IllegalStateException("Unable to load resources from " + locations,
ex);
}
return resources;
}
private void runScripts(List<Resource> resources, String username, String password) {
......
......@@ -16,7 +16,10 @@
package org.springframework.boot.autoconfigure.jdbc;
import java.io.IOException;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
import javax.sql.DataSource;
......@@ -34,6 +37,11 @@ import org.springframework.context.annotation.AnnotationConfigApplicationContext
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternUtils;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcOperations;
import org.springframework.jdbc.core.JdbcTemplate;
......@@ -181,15 +189,11 @@ public class DataSourceInitializerTests {
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class);
this.context.publishEvent(new DataSourceInitializedEvent(dataSource));
assertThat(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource).isTrue();
assertThat(dataSource).isNotNull();
JdbcOperations template = new JdbcTemplate(dataSource);
try {
template.queryForObject("SELECT COUNT(*) from BAR", Integer.class);
fail("Query should have failed as BAR table does not exist");
......@@ -245,6 +249,28 @@ public class DataSourceInitializerTests {
}
}
@Test
public void multipleScriptsAppliedInLexicalOrder() throws Exception {
EnvironmentTestUtils.addEnvironment(this.context,
"spring.datasource.initialize:true",
"spring.datasource.schema:" + ClassUtils
.addResourcePathToPackagePath(getClass(), "lexical-schema-*.sql"),
"spring.datasource.data:" + ClassUtils
.addResourcePathToPackagePath(getClass(), "data.sql"));
this.context.register(DataSourceAutoConfiguration.class,
PropertyPlaceholderAutoConfiguration.class);
ReverseOrderResourceLoader resourceLoader = new ReverseOrderResourceLoader(
new DefaultResourceLoader());
this.context.setResourceLoader(resourceLoader);
this.context.refresh();
DataSource dataSource = this.context.getBean(DataSource.class);
assertThat(dataSource instanceof org.apache.tomcat.jdbc.pool.DataSource).isTrue();
assertThat(dataSource).isNotNull();
JdbcOperations template = new JdbcTemplate(dataSource);
assertThat(template.queryForObject("SELECT COUNT(*) from FOO", Integer.class))
.isEqualTo(1);
}
@Configuration
@EnableConfigurationProperties
protected static class TwoDataSources {
......@@ -264,4 +290,42 @@ public class DataSourceInitializerTests {
}
/**
* {@link ResourcePatternResolver} used to ensure consistently wrong resource
* ordering.
*/
private static class ReverseOrderResourceLoader implements ResourcePatternResolver {
private final ResourcePatternResolver resolver;
ReverseOrderResourceLoader(ResourceLoader loader) {
this.resolver = ResourcePatternUtils.getResourcePatternResolver(loader);
}
@Override
public Resource getResource(String location) {
return this.resolver.getResource(location);
}
@Override
public ClassLoader getClassLoader() {
return this.resolver.getClassLoader();
}
@Override
public Resource[] getResources(String locationPattern) throws IOException {
Resource[] resources = this.resolver.getResources(locationPattern);
Arrays.sort(resources, new Comparator<Resource>() {
@Override
public int compare(Resource r1, Resource r2) {
return r2.getFilename().compareTo(r1.getFilename());
}
});
return resources;
}
}
}
ALTER TABLE FOO DROP COLUMN todrop;
ALTER TABLE FOO ADD COLUMN name VARCHAR(30);
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment