Browse Source

Use lexical ordered DataSourceInitializer patterns

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

Fixes gh-6316
pull/6328/merge
Phillip Webb 10 years ago
parent
commit
f4df9d9767
  1. 33
      spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java
  2. 72
      spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerTests.java
  3. 4
      spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/jdbc/lexical-schema-aaa.sql
  4. 2
      spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/jdbc/lexical-schema-bbb.sql

33
spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializer.java

@ -16,8 +16,8 @@ @@ -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; @@ -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 @@ -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) {

72
spring-boot-autoconfigure/src/test/java/org/springframework/boot/autoconfigure/jdbc/DataSourceInitializerTests.java

@ -16,7 +16,10 @@ @@ -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 @@ -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 { @@ -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 { @@ -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 { @@ -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;
}
}
}

4
spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/jdbc/lexical-schema-aaa.sql

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
CREATE TABLE FOO (
id INTEGER IDENTITY PRIMARY KEY,
todrop VARCHAR(30),
);

2
spring-boot-autoconfigure/src/test/resources/org/springframework/boot/autoconfigure/jdbc/lexical-schema-bbb.sql

@ -0,0 +1,2 @@ @@ -0,0 +1,2 @@
ALTER TABLE FOO DROP COLUMN todrop;
ALTER TABLE FOO ADD COLUMN name VARCHAR(30);
Loading…
Cancel
Save