Skip to content

Commit 46cafec

Browse files
committed
#56 improve processing @ConditionalOnBean(DataSource.class)
1 parent f7842e1 commit 46cafec

File tree

1 file changed

+85
-10
lines changed

1 file changed

+85
-10
lines changed

embedded-database-spring-test/src/main/java/io/zonky/test/db/EmbeddedDatabaseContextCustomizerFactory.java

Lines changed: 85 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,12 @@
3838
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
3939
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
4040
import org.springframework.beans.factory.support.RootBeanDefinition;
41+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
42+
import org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate;
4143
import org.springframework.context.ApplicationContext;
4244
import org.springframework.context.ConfigurableApplicationContext;
4345
import org.springframework.context.EnvironmentAware;
46+
import org.springframework.context.annotation.Bean;
4447
import org.springframework.context.annotation.Configuration;
4548
import org.springframework.context.annotation.DeferredImportSelector;
4649
import org.springframework.context.annotation.Import;
@@ -55,7 +58,9 @@
5558
import org.springframework.test.context.ContextCustomizerFactory;
5659
import org.springframework.test.context.MergedContextConfiguration;
5760
import org.springframework.util.Assert;
61+
import org.springframework.util.ClassUtils;
5862
import org.springframework.util.ObjectUtils;
63+
import org.springframework.util.StringUtils;
5964

6065
import javax.sql.DataSource;
6166
import java.util.LinkedHashSet;
@@ -101,12 +106,21 @@ public EmbeddedDatabaseContextCustomizer(Set<DatabaseDefinition> databaseDefinit
101106

102107
@Override
103108
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
104-
context.addBeanFactoryPostProcessor(new EnvironmentPostProcessor(databaseDefinitions, context.getEnvironment()));
109+
context.addBeanFactoryPostProcessor(new EnvironmentPostProcessor(context.getEnvironment()));
105110

106111
BeanDefinitionRegistry registry = getBeanDefinitionRegistry(context);
107112

108-
RootBeanDefinition configDefinition = new RootBeanDefinition(EmbeddedDatabaseConfiguration.class);
109-
registry.registerBeanDefinition(EmbeddedDatabaseConfiguration.BEAN_NAME, configDefinition);
113+
// these configurations are necessary only for auto-configuration phase
114+
if (databaseDefinitions.size() == 1) {
115+
RootBeanDefinition preConfigDefinition = new RootBeanDefinition(SingleDatabaseConfiguration.class);
116+
registry.registerBeanDefinition(SingleDatabaseConfiguration.BEAN_NAME, preConfigDefinition);
117+
} else if (databaseDefinitions.size() > 1) {
118+
RootBeanDefinition preConfigDefinition = new RootBeanDefinition(MultipleDatabasesConfiguration.class);
119+
registry.registerBeanDefinition(MultipleDatabasesConfiguration.BEAN_NAME, preConfigDefinition);
120+
}
121+
122+
RootBeanDefinition mainConfigDefinition = new RootBeanDefinition(EmbeddedDatabaseConfiguration.class);
123+
registry.registerBeanDefinition(EmbeddedDatabaseConfiguration.BEAN_NAME, mainConfigDefinition);
110124

111125
RootBeanDefinition registrarDefinition = new RootBeanDefinition(EmbeddedDatabaseRegistrar.class);
112126
registrarDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, databaseDefinitions);
@@ -132,22 +146,17 @@ public int hashCode() {
132146

133147
protected static class EnvironmentPostProcessor implements BeanDefinitionRegistryPostProcessor {
134148

135-
private final Set<DatabaseDefinition> databaseDefinitions;
136149
private final ConfigurableEnvironment environment;
137150

138-
public EnvironmentPostProcessor(Set<DatabaseDefinition> databaseDefinitions, ConfigurableEnvironment environment) {
139-
this.databaseDefinitions = databaseDefinitions;
151+
public EnvironmentPostProcessor(ConfigurableEnvironment environment) {
140152
this.environment = environment;
141153
}
142154

143155
@Override
144156
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
145-
Replace zonkyDatabaseReplace = getDatabaseReplaceMode(environment, databaseDefinitions);
146-
String springDatabaseReplace = zonkyDatabaseReplace == Replace.NONE ? "NONE" : "AUTO_CONFIGURED";
147-
148157
environment.getPropertySources().addFirst(new MapPropertySource(
149158
EmbeddedDatabaseContextCustomizer.class.getSimpleName(),
150-
ImmutableMap.of("spring.test.database.replace", springDatabaseReplace)));
159+
ImmutableMap.of("spring.test.database.replace", "NONE")));
151160
}
152161

153162
@Override
@@ -156,6 +165,65 @@ public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
156165
}
157166
}
158167

168+
@Configuration
169+
@Import(PreAutoConfigurationImportSelector.class)
170+
protected static class SingleDatabaseConfiguration {
171+
172+
protected static final String BEAN_NAME = SingleDatabaseConfiguration.class.getName();
173+
174+
}
175+
176+
@Configuration
177+
@Import(PreAutoConfigurationImportSelector.class)
178+
protected static class MultipleDatabasesConfiguration {
179+
180+
protected static final String BEAN_NAME = MultipleDatabasesConfiguration.class.getName();
181+
182+
}
183+
184+
protected static class PreAutoConfigurationImportSelector implements DeferredImportSelector, Ordered {
185+
186+
@Override
187+
public String[] selectImports(AnnotationMetadata annotationMetadata) {
188+
if (!ClassUtils.isPresent("org.springframework.boot.autoconfigure.condition.ConditionalOnBean", null)) {
189+
return new String[0];
190+
}
191+
String className = annotationMetadata.getClassName();
192+
if (SingleDatabaseConfiguration.BEAN_NAME.equals(className)) {
193+
return new String[] { PrimaryDataSourceAutoConfiguration.class.getName() };
194+
}
195+
if (MultipleDatabasesConfiguration.BEAN_NAME.equals(className)) {
196+
return new String[] { PrimaryDataSourceAutoConfiguration.class.getName(), SecondaryDataSourceAutoConfiguration.class.getName() };
197+
}
198+
throw new IllegalStateException("Unexpected selector configuration class: " + className);
199+
}
200+
201+
@Override
202+
public int getOrder() {
203+
return Ordered.LOWEST_PRECEDENCE - 3;
204+
}
205+
}
206+
207+
@Configuration
208+
protected static class PrimaryDataSourceAutoConfiguration {
209+
210+
@Bean
211+
@ConditionalOnMissingBean
212+
public DataSource embeddedDataSource1() {
213+
return null;
214+
}
215+
}
216+
217+
@Configuration
218+
protected static class SecondaryDataSourceAutoConfiguration {
219+
220+
@Bean
221+
@ConditionalOnSingleCandidate
222+
public DataSource embeddedDataSource2() {
223+
return null;
224+
}
225+
}
226+
159227
@Configuration
160228
@Import(EmbeddedDatabaseConfiguration.Selector.class)
161229
protected static class EmbeddedDatabaseConfiguration {
@@ -199,6 +267,13 @@ public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) {
199267
"Embedded Database Auto-configuration can only be used with a ConfigurableListableBeanFactory");
200268
ConfigurableListableBeanFactory beanFactory = (ConfigurableListableBeanFactory) registry;
201269

270+
if (registry.containsBeanDefinition("embeddedDataSource1")) {
271+
registry.removeBeanDefinition("embeddedDataSource1");
272+
}
273+
if (registry.containsBeanDefinition("embeddedDataSource2")) {
274+
registry.removeBeanDefinition("embeddedDataSource2");
275+
}
276+
202277
Replace replace = getDatabaseReplaceMode(environment, databaseDefinitions);
203278
if (replace == Replace.NONE) {
204279
logger.info("The use of the embedded database has been disabled");

0 commit comments

Comments
 (0)