Skip to content

Commit

Permalink
Introduce database-name in <jdbc:embedded-database>
Browse files Browse the repository at this point in the history
Prior to this commit, the EmbeddedDatabaseBeanDefinitionParser set the
name of the embedded database that it configured to the value of its
'id'. This made it impossible to assign unique names to embedded
databases if the same bean 'id' (e.g, 'dataSource') was used across
multiple application contexts loaded within the same JVM, which is
often the case within an integration test suite. In contrast, the
EmbeddedDatabaseBuilder already provides support for setting the name
in Java Config. Thus there is a disconnect between XML and Java
configuration.

This commit addresses this issue by introducing a 'database-name'
attribute in <jdbc:embedded-database />. This allows developers to set
unique names for embedded databases -- for example, via a SpEL
expression or a property placeholder that is influenced by the current
active bean definition profiles.

Issue: SPR-12835
  • Loading branch information
sbrannen committed Mar 20, 2015
1 parent 7e2f12c commit c36c6cb
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 14 deletions.
Expand Up @@ -43,10 +43,16 @@
*/
class EmbeddedDatabaseBeanDefinitionParser extends AbstractBeanDefinitionParser {

/**
* Constant for the "database-name" attribute.
*/
static final String DB_NAME_ATTRIBUTE = "database-name";


@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(EmbeddedDatabaseFactoryBean.class);
useIdAsDatabaseNameIfGiven(element, builder);
setDatabaseName(element, builder);
setDatabaseType(element, builder);
DatabasePopulatorConfigUtils.setDatabasePopulator(element, builder);
builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
Expand All @@ -58,11 +64,20 @@ protected boolean shouldGenerateIdAsFallback() {
return true;
}

private void useIdAsDatabaseNameIfGiven(Element element, BeanDefinitionBuilder builder) {
String id = element.getAttribute(ID_ATTRIBUTE);
if (StringUtils.hasText(id)) {
builder.addPropertyValue("databaseName", id);
private void setDatabaseName(Element element, BeanDefinitionBuilder builder) {
// 1) Check for an explicit database name
String name = element.getAttribute(DB_NAME_ATTRIBUTE);

// 2) Fall back to an implicit database name based on the ID
if (!StringUtils.hasText(name)) {
name = element.getAttribute(ID_ATTRIBUTE);
}

if (StringUtils.hasText(name)) {
builder.addPropertyValue("databaseName", name);
}

// 3) Let EmbeddedDatabaseFactory set the default "testdb" name
}

private void setDatabaseType(Element element, BeanDefinitionBuilder builder) {
Expand Down
Expand Up @@ -34,6 +34,16 @@
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="database-name" type="xsd:string" default="">
<xsd:annotation>
<xsd:documentation><![CDATA[
The name to assign to the embedded database. Note that this is not the
bean name but rather the name of the embedded database as used in the JDBC
connection URL for the database. Defaults to "testdb" if an explicit bean
'id' has not been provided.
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="type" type="databaseType" default="HSQL">
<xsd:annotation>
<xsd:documentation><![CDATA[
Expand Down
Expand Up @@ -31,13 +31,15 @@
import org.springframework.core.io.ClassPathResource;
import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.datasource.AbstractDriverBasedDataSource;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactoryBean;
import org.springframework.jdbc.datasource.init.DataSourceInitializer;
import org.springframework.tests.Assume;
import org.springframework.tests.TestGroup;

import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.*;
import static org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseFactory.*;

/**
* @author Dave Syer
Expand Down Expand Up @@ -65,13 +67,24 @@ public void createEmbeddedDatabaseAgain() throws Exception {
}

@Test
public void createWithAnonymousDataSource() throws Exception {
assertCorrectSetupAndCloseContextForSingleDataSource("jdbc-config-anonymous-datasource.xml", 1);
public void createWithResourcePattern() throws Exception {
assertCorrectSetup("jdbc-config-pattern.xml", "dataSource");
}

@Test
public void createWithResourcePattern() throws Exception {
assertCorrectSetup("jdbc-config-pattern.xml", "dataSource");
public void createWithAnonymousDataSourceAndDefaultDatabaseName() throws Exception {
assertCorrectSetupForSingleDataSource("jdbc-config-db-name-default-and-anonymous-datasource.xml",
DEFAULT_DATABASE_NAME);
}

@Test
public void createWithImplicitDatabaseName() throws Exception {
assertCorrectSetupForSingleDataSource("jdbc-config-db-name-implicit.xml", "dataSource");
}

@Test
public void createWithExplicitDatabaseName() throws Exception {
assertCorrectSetupForSingleDataSource("jdbc-config-db-name-explicit.xml", "customDbName");
}

@Test
Expand Down Expand Up @@ -165,21 +178,25 @@ private void assertCorrectSetupAndCloseContext(String file, int count, String...
try {
for (String dataSourceName : dataSources) {
DataSource dataSource = context.getBean(dataSourceName, DataSource.class);
JdbcTemplate template = new JdbcTemplate(dataSource);
assertNumRowsInTestTable(template, count);
assertNumRowsInTestTable(new JdbcTemplate(dataSource), count);
assertTrue(dataSource instanceof AbstractDriverBasedDataSource);
AbstractDriverBasedDataSource adbDataSource = (AbstractDriverBasedDataSource) dataSource;
assertThat(adbDataSource.getUrl(), containsString(dataSourceName));
}
}
finally {
context.close();
}
}

private void assertCorrectSetupAndCloseContextForSingleDataSource(String file, int count) {
private void assertCorrectSetupForSingleDataSource(String file, String dbName) {
ConfigurableApplicationContext context = context(file);
try {
DataSource dataSource = context.getBean(DataSource.class);
JdbcTemplate template = new JdbcTemplate(dataSource);
assertNumRowsInTestTable(template, count);
assertNumRowsInTestTable(new JdbcTemplate(dataSource), 1);
assertTrue(dataSource instanceof AbstractDriverBasedDataSource);
AbstractDriverBasedDataSource adbDataSource = (AbstractDriverBasedDataSource) dataSource;
assertThat(adbDataSource.getUrl(), containsString(dbName));
}
finally {
context.close();
Expand Down
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.2.xsd">

<embedded-database id="dataSource" database-name="customDbName">
<script location="classpath:org/springframework/jdbc/config/db-schema.sql" />
<script location="classpath:org/springframework/jdbc/config/db-test-data.sql" />
</embedded-database>

</beans:beans>
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns="http://www.springframework.org/schema/jdbc"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.2.xsd">

<embedded-database id="dataSource">
<script location="classpath:org/springframework/jdbc/config/db-schema.sql" />
<script location="classpath:org/springframework/jdbc/config/db-test-data.sql" />
</embedded-database>

</beans:beans>

0 comments on commit c36c6cb

Please sign in to comment.